1
2
3
4
5
6
7
8
9 package tsukuba_bunko.peko.scenario.text;
10
11 import java.awt.Dimension;
12
13 import java.awt.font.LineBreakMeasurer;
14 import java.awt.font.TextAttribute;
15 import java.awt.font.TextLayout;
16
17 import java.text.AttributedString;
18
19 import tsukuba_bunko.peko.Logger;
20
21 import tsukuba_bunko.peko.canvas.text.Line;
22 import tsukuba_bunko.peko.canvas.text.Page;
23
24 import tsukuba_bunko.peko.resource.ResourceManager;
25
26 import tsukuba_bunko.peko.scenario.Coordinator;
27 import tsukuba_bunko.peko.scenario.SceneContext;
28
29
30 /***
31 * TextCanvas への操作を取り持つコーディネータモジュールです。
32 * @author $Author: ppoi $
33 * @version $Revision: 1.2 $
34 */
35 public class TextCoordinator extends Coordinator {
36
37 /***
38 * Page の設定を行ったかどうか
39 */
40 protected boolean _pageConfigured = false;
41
42 /***
43 * 行間隔
44 */
45 protected float _lineSpan = 0f;
46
47 /***
48 * 最終行
49 */
50 protected Line _lastLine = null;
51
52
53 /***
54 * Dimension cache
55 */
56 protected Dimension _sizeCache = new Dimension();
57
58
59 /***
60 * <code>TextCoordinator</code> のインスタンスを生成します。
61 */
62 public TextCoordinator()
63 {
64 super();
65 }
66
67
68 public void prepare( SceneContext context, Thread activeThread )
69 {
70 super.prepare( context, activeThread );
71 _pageConfigured = false;
72 _lastLine = null;
73 }
74
75
76 /***
77 * TextCanvas への操作を開始します。
78 */
79 public void begin()
80 {
81 if( isActiveThread() ) {
82 _lastLine = null;
83 getActionControler().setSaveEnabled( true );
84 }
85 }
86
87 /***
88 * TextCanvas への操作を終了し、キャンバスの状態を確定します。
89 */
90 public void commit()
91 {
92 if( isActiveThread() ) {
93 getActionControler().setSaveEnabled( false );
94 getCurrentPage().commit();
95 }
96 }
97
98 /***
99 * 表示する文章を TextCanvsa に送信します。
100 * @param text 表示する文章
101 */
102 public void pushText( String text )
103 {
104 if( !isActiveThread() ) {
105 return;
106 }
107
108 Page page = getCurrentPage();
109 if( !_pageConfigured ) {
110 PageConfigurator.configure( page, getSceneContext() );
111 _pageConfigured = true;
112 _lineSpan = getLineSpan();
113 }
114
115 int length = text.length();
116 if( length == 0 ) {
117 Logger.debug( "[scnario.text] empty string is pecified." );
118 return;
119 }
120
121 if( _lastLine != null ) {
122 text = _lastLine.getText() + text;
123 length = text.length();
124 }
125 Logger.debug( text );
126
127 AttributedString astring = new AttributedString( text );
128 astring.addAttribute( TextAttribute.FONT, page.getDefaultFont() );
129 astring.addAttribute( TextAttribute.FOREGROUND, page.getForeground() );
130
131 LineBreakMeasurer lbm = new LineBreakMeasurer( astring.getIterator(), page.getFontRenderContext() );
132 float maxWidth = page.getMaxLineWidth();
133 float lineSpan = _lineSpan;
134 boolean conflictWait = false;
135 TextLayout layout = null;
136 Line line = null;
137
138 layout = lbm.nextLayout( maxWidth );
139 line = new Line();
140 line.setTextLayout( layout );
141 line.setText( text.substring(0, lbm.getPosition()) );
142 line.setForeground( page.getForeground() );
143 line.setShadowColor( page.getShadow() );
144
145 if( _lastLine == null ) {
146 if( isActiveThread() ) {
147 line.setLineSpan( lineSpan );
148 if( !page.isAdaptive(line) ) {
149 page = advancesNewPage();
150 }
151 page.addLine( line );
152 }
153 else {
154 return;
155 }
156 }
157 else {
158 line.setLineSpan( lineSpan );
159 if( isActiveThread() ) {
160 page.setLine( (page.getLineCount() - 1), line );
161 if( _lastLine.getText().equals(line.getText()) ) {
162 conflictWait = true;
163 }
164 }
165 else {
166 return;
167 }
168 }
169 _lastLine = line;
170
171 int lastLinePosition = 0;
172 while( (lastLinePosition = lbm.getPosition()) < length ) {
173 line = new Line();
174 line.setTextLayout( lbm.nextLayout(maxWidth) );
175 line.setLineSpan( lineSpan );
176 line.setText( text.substring(lastLinePosition, lbm.getPosition()) );
177 line.setForeground( page.getForeground() );
178 line.setShadowColor( page.getShadow() );
179 if( isActiveThread() ) {
180 if( !page.isAdaptive(line) ) {
181 if( conflictWait ) {
182 conflictWait = false;
183 }
184 else {
185 page.updateContents();
186 stop();
187 }
188 page = advancesNewPage();
189 }
190 if( page != null ) {
191 page.addLine( line );
192 conflictWait = false;
193 }
194 else {
195 return;
196 }
197 _lastLine = line;
198 }
199 else {
200 return;
201 }
202 }
203 if( isActiveThread() ) {
204 page.updateContents();
205 }
206 }
207
208 /***
209 * 現在表示中のページを取得します。
210 * @return 現在表示中のページ
211 */
212 public Page getCurrentPage()
213 {
214 return getCanvasManager().getCurrentPage();
215 }
216
217 /***
218 * 新しいページに切り替え、新しいページを取得します。
219 * @return 新しいページ
220 */
221 public Page advancesNewPage()
222 {
223 if( isActiveThread() ) {
224 return getCanvasManager().advancesNewPage();
225 }
226 else {
227 return null;
228 }
229 }
230
231 /***
232 * 処理を一時停止します。
233 */
234 protected void stop()
235 {
236 if( isActiveThread() ) {
237 getActionControler().stop();
238 }
239 }
240
241 /***
242 * 行間隔を取得します。
243 * @return 行間隔
244 */
245 protected float getLineSpan()
246 {
247 SceneContext context = getSceneContext();
248 String value = context.getProperty( PropertyIDs.CANVAS_TEXT_LINESPAN );
249 if( value != null ) {
250 try {
251 return Float.parseFloat( value );
252 }
253 catch( Exception e ) {
254 Logger.warn( MessageIDs.SCN2002W, e );
255 }
256 }
257
258 ResourceManager resources = ResourceManager.getInstance();
259 Float lineSpan = (Float)resources.getResource( ResourceIDs.CANVAS_TEXT_LINESPAN );
260 if( lineSpan != null ) {
261 return lineSpan.floatValue();
262 }
263 else {
264 Logger.warn( MessageIDs.SCN2001W, new Object[]{"20.0"} );
265 return 20f;
266 }
267 }
268 }