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: ActionControler.java,v 1.6 2005/07/23 18:45:12 ppoi Exp $
    18   */
    19  package tsukuba_bunko.peko;
    20
    21  import	java.awt.event.ActionListener;
    22  import	java.awt.event.MouseEvent;
    23  import	java.awt.event.MouseListener;
    24  import	java.awt.event.KeyEvent;
    25  import	java.awt.event.KeyListener;
    26
    27  import	java.text.MessageFormat;
    28
    29  import	java.util.Timer;
    30  import	java.util.TimerTask;
    31
    32  import	javax.swing.ButtonGroup;
    33  import	javax.swing.ImageIcon;
    34  import	javax.swing.JButton;
    35  import	javax.swing.JCheckBoxMenuItem;
    36  import	javax.swing.JDialog;
    37  import	javax.swing.JFrame;
    38  import	javax.swing.JMenu;
    39  import	javax.swing.JMenuBar;
    40  import	javax.swing.JMenuItem;
    41  import	javax.swing.JOptionPane;
    42  import	javax.swing.JRadioButtonMenuItem;
    43  import	javax.swing.KeyStroke;
    44
    45  import	tsukuba_bunko.util.GenericListener;
    46
    47  import	tsukuba_bunko.peko.canvas.CanvasManager;
    48
    49  import	tsukuba_bunko.peko.resource.ResourceManager;
    50
    51
    52  /***
    53   * プレイヤーの操作を受け付けるコントローラです。
    54   * @author	$Author: ppoi $
    55   * @version	$Revision: 1.6 $
    56   */
    57  public class ActionControler	implements KeyListener, MouseListener	{
    58
    59  	/***
    60  	 * プレイヤーが操作するまで停止するストップモード(デフォルト)
    61  	 */
    62  	public static final long	SM_DEFAULT = -1;
    63
    64  	/***
    65  	 * ノンストップモード
    66  	 */
    67  	public static final long	SM_NONSTOP = 0;
    68
    69
    70  	/***
    71  	 * 早送りプレイ(次の選択肢までスキップ)モード
    72  	 */
    73  	public static final int	PM_SKIP = 1;
    74
    75  	/***
    76  	 * 通常プレイモード
    77  	 */
    78  	public static final int PM_NORMAL = 0;
    79
    80  	/***
    81  	 * 自動送りプレイモード
    82  	 */
    83  	public static final int	PM_AUTOMATIC = 2;
    84
    85
    86  	/***
    87  	 */
    88  	private Object	_lock = this;
    89
    90  	/***
    91  	 * 有効かどうか
    92  	 */
    93  	private boolean	_activity = false;
    94
    95  	/***
    96  	 * プレイモード
    97  	 */
    98  	private int	_playMode = -1;
    99
    100 	/***
    101 	 * プレイモード変更ボタン(メニュー)リスト
    102 	 */
    103 	private JMenuItem[]	_buttons = new JMenuItem[3];
    104
    105 	/***
    106 	 * エフェクトを使用しないメニュー
    107 	 */
    108 	private JMenuItem	_usingEffectMenu = null;
    109
    110 	/***
    111 	 * セーブメニュー
    112 	 */
    113 	private JMenuItem	_saveMenu = null;
    114
    115 	/***
    116 	 * ロードメニュー
    117 	 */
    118 	private JMenuItem	_loadMenu = null;
    119
    120 	/***
    121 	 * タイトルに戻るメニュー
    122 	 */
    123 	private JMenuItem	_returnTileMenu = null;
    124
    125 	/***
    126 	 * 過去の文章メニュー
    127 	 */
    128 	private JMenuItem	_readAgainMenu = null;
    129
    130 	/***
    131 	 * タイマー
    132 	 */
    133 	private Timer	_timer = new Timer( true );
    134
    135 	/***
    136 	 * 最新のタスク
    137 	 */
    138 	private TimerTask	_lastTask = null;
    139
    140
    141 	/***
    142 	 * 読み返しコントローラ
    143 	 */
    144 	private TextHistoryControler	_readAgainControler = null;
    145
    146 	/***
    147 	 * 最後に押されたキーのキーコード
    148 	 */
    149 	private int	_lastKeyCode = -1;
    150
    151 	/***
    152 	 * active 待ちかどうか
    153 	 */
    154 	private boolean	_waitingActivate = false;
    155
    156 	/***
    157 	 * テキストを隠しているかどうか
    158 	 */
    159 	private boolean	_hiddenText = false;
    160
    161
    162 	/***
    163 	 * <code>ActionControler</code> のインスタンスを作成します。
    164 	 */
    165 	public ActionControler()
    166 	{
    167 		super();
    168 		prepareMenuBar();
    169 		setPlayModeToNormal();
    170 	}
    171
    172 	/***
    173 	 * ActionContorler を有効にするかどうかを設定します。
    174 	 * @param	activity	有効にする場合 <code>false</code>、それ以外 <code>false</code>。
    175 	 */
    176 	public void setActive( boolean activity )
    177 	{
    178 		_activity = activity;
    179 		if( !activity )	{
    180 			_lastKeyCode = -1;
    181 		}
    182 		else if( _playMode != ActionControler.PM_NORMAL )	{
    183 			if( _waitingActivate )	{
    184 				synchronized( _lock )	{
    185 					if( _waitingActivate )	{
    186 						_lock.notify();
    187 					}
    188 				}
    189 			}
    190 		}
    191 	}
    192
    193 	/***
    194 	 * ActionControler が有効かどうかを判定します。
    195 	 * @return	有効な場合 <code>true</code>、それ以外 <code>false</code>。
    196 	 */
    197 	public boolean isActive()
    198 	{
    199 		return _activity && !PekoSystem.getInstance().getCanvasManager().isShowingSelect();
    200 	}
    201
    202 	/***
    203 	 * セーブ機能の有効／無効を設定します。
    204 	 * @param	enabled	有効にする場合 <code>true</code>、それ以外の場合 <code>false</code>
    205 	 */
    206 	public synchronized void setSaveEnabled( boolean enabled )
    207 	{
    208 		_saveMenu.setEnabled( enabled );
    209 	}
    210
    211 	/***
    212 	 * 現在のプレイモードを取得します。
    213 	 */
    214 	public int getPlayMode()
    215 	{
    216 		return _playMode;
    217 	}
    218
    219 	/***
    220 	 * プレイモードを設定します。
    221 	 * @param	playMode	プレイモード。<code>PM_FORWARD</code>、<code>PM_NORMAL</code>、<code>PM_AUTOMATIC</code> から選択。
    222 	 */
    223 	protected void setPlayMode( int playMode )
    224 	{
    225 		_playMode = playMode;
    226 		_buttons[playMode].setSelected( true );
    227 		if( playMode == ActionControler.PM_SKIP )	{
    228 			_readAgainMenu.setEnabled( false );
    229 		}
    230 		else if( !_readAgainMenu.isEnabled() )	{
    231 			_readAgainMenu.setEnabled( true );
    232 		}
    233 		PekoSystem.getInstance().getCanvasManager().getStageCanvas().setUsingEffect( !_usingEffectMenu.isSelected() && (playMode != ActionControler.PM_SKIP) );
    234 		if( (_playMode != ActionControler.PM_NORMAL) && !PekoSystem.getInstance().getCanvasManager().isShowingSelect() )	{
    235 			start();
    236 		}
    237 	}
    238
    239 	/***
    240 	 * プレイモードを「早送り」に設定します。
    241 	 */
    242 	public void setPlayModeToSKip()
    243 	{
    244 		setPlayMode( ActionControler.PM_SKIP );
    245 	}
    246
    247 	/***
    248 	 * プレイモードを「通常」に設定します。
    249 	 */
    250 	public void setPlayModeToNormal()
    251 	{
    252 		setPlayMode( ActionControler.PM_NORMAL );
    253 	}
    254
    255 	/***
    256 	 * プレイモードを「自動」に設定します。
    257 	 */
    258 	public void setPlayModeToAutomatic()
    259 	{
    260 		setPlayMode( ActionControler.PM_AUTOMATIC );
    261 	}
    262
    263 	/***
    264 	 * 画像切り替えエフェクトを使用するかどうかを切り替えます。
    265 	 */
    266 	public void changeUsingEffect()
    267 	{
    268 		PekoSystem.getInstance().getCanvasManager().getStageCanvas().setUsingEffect( !_usingEffectMenu.isSelected() && (_playMode != ActionControler.PM_SKIP) );
    269 	}
    270
    271 	/***
    272 	 * 読み返しコントローラを表示します。
    273 	 */
    274 	public void showReadAgain()
    275 	{
    276 		setActive( false );
    277 		_saveMenu.setEnabled( false );
    278 		_loadMenu.setEnabled( false );
    279 		_returnTileMenu.setEnabled( false );
    280 		_readAgainMenu.setEnabled( false );
    281 		if( _readAgainControler == null )	{
    282 			_readAgainControler = new TextHistoryControler();
    283 			_readAgainControler.setLocationRelativeTo( PekoSystem.getInstance().getMainWindow() );
    284 		}
    285 		_readAgainControler.setVisible( true );
    286 		setActive( true );
    287 		_saveMenu.setEnabled( true );
    288 		_loadMenu.setEnabled( true );
    289 		_returnTileMenu.setEnabled( true );
    290 		_readAgainMenu.setEnabled( true );
    291 	}
    292
    293 	/***
    294 	 * ロードダイアログを表示します。
    295 	 */
    296 	public void showLoadDialog()
    297 	{
    298 		setActive( false );
    299 		_saveMenu.setEnabled( false );
    300 		_loadMenu.setEnabled( false );
    301 		_returnTileMenu.setEnabled( false );
    302 		_readAgainMenu.setEnabled( false );
    303 		PekoSystem	system = PekoSystem.getInstance();
    304 		if( !system.load() )	{
    305 			setActive( true );
    306 		}
    307 		_saveMenu.setEnabled( true );
    308 		_loadMenu.setEnabled( true );
    309 		_returnTileMenu.setEnabled( true );
    310 		_readAgainMenu.setEnabled( true );
    311 	}
    312
    313 	/***
    314 	 * セーブダイアログを表示します。
    315 	 */
    316 	public synchronized void showSaveDialog()
    317 	{
    318 		PekoSystem	system = PekoSystem.getInstance();
    319 		setActive( false );
    320 		_saveMenu.setEnabled( false );
    321 		_loadMenu.setEnabled( false );
    322 		_returnTileMenu.setEnabled( false );
    323 		_readAgainMenu.setEnabled( false );
    324 		system.save();
    325 		_saveMenu.setEnabled( true );
    326 		_loadMenu.setEnabled( true );
    327 		_returnTileMenu.setEnabled( true );
    328 		_readAgainMenu.setEnabled( true );
    329 		setActive( true );
    330 	}
    331
    332 	/***
    333 	 * タイトル画面に戻ります。
    334 	 */
    335 	public void returnTitle()
    336 	{
    337 		returnTitle( false );
    338 	}
    339
    340 	/***
    341 	 * タイトル画面に戻ります。
    342 	 */
    343 	public void returnTitle( boolean silence )
    344 	{
    345 		setActive( false );
    346 		setPlayMode( ActionControler.PM_NORMAL );
    347 		_saveMenu.setEnabled( false );
    348 		_loadMenu.setEnabled( false );
    349 		_returnTileMenu.setEnabled( false );
    350 		_readAgainMenu.setEnabled( false );
    351 		if( silence )	{
    352 			PekoSystem.getInstance().showTitle();
    353 		}
    354 		else	{
    355 			ResourceManager	resources = ResourceManager.getInstance();
    356 			String	message = (String)resources.getResource( "peko.dialog.return-title.message" );
    357 			if( message == null )	{
    358 				message = "Are you return title ?";
    359 			}
    360
    361 			String	title = (String)resources.getResource( "peko.dialog.return-title.title" );
    362 			if( title == null )	{
    363 				title = "Confirm";
    364 			}
    365
    366 			if( JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(PekoSystem.getInstance().getMainWindow(), message, title, JOptionPane.OK_CANCEL_OPTION) )	{
    367 				PekoSystem.getInstance().showTitle();
    368 			}
    369 			else	{
    370 				setActive( true );
    371 			}
    372 		}
    373 		_saveMenu.setEnabled( true );
    374 		_loadMenu.setEnabled( true );
    375 		_returnTileMenu.setEnabled( true );
    376 		_readAgainMenu.setEnabled( true );
    377 	}
    378
    379
    380 	/***
    381 	 * {@link #stop()} により停止されたスレッドを再開します。
    382 	 */
    383 	public void start()
    384 	{
    385 		synchronized( _lock )	{
    386 			if( _lastTask != null )	{
    387 				_lastTask.cancel();
    388 			}
    389 			_lastTask = null;
    390 			_lock.notify();
    391 			Logger.debug( "[system.controler] notify to finish wait." );
    392 		}
    393 	}
    394
    395 	/***
    396 	 * プレイヤーがアクションを起こすまで現在のスレッドを停止します。
    397 	 */
    398 	public void stop()
    399 	{
    400 		stop( ActionControler.SM_DEFAULT );
    401 	}
    402
    403 	/***
    404 	 * 現在のスレッドを停止します。
    405 	 * @param	wait	待ち時間。プレイヤーが操作するまでストップする場合は <code>SM_DEFAULT</code> を、無停止の場合は <code>SM_NONSTOP</code> を指定する。
    406 	 */
    407 	public void stop( long wait )
    408 	{
    409 		Logger.debug( "[system.controler] stop :" + wait );
    410 		if( (wait == 0) || (_playMode == ActionControler.PM_SKIP) )	{
    411 			//NOOP
    412 		}
    413 		else if( wait < 0 )	{
    414 			synchronized( _lock )	{
    415 				try	{
    416 					if( (_playMode == ActionControler.PM_AUTOMATIC) && !PekoSystem.getInstance().getCanvasManager().isShowingSelect() )	{
    417 						TimerTask	task = new TimerTask()	{
    418 							public void run()	{
    419 								synchronized( _lock )	{
    420 									_lock.notify();
    421 								}
    422 							}
    423 						};
    424 						_timer.schedule( task, 1000L );
    425 						_lastTask = task;
    426 					}
    427 					_lock.wait();
    428 				}
    429 				catch( InterruptedException ie )	{
    430 					Logger.debug( "[system.action] interrupted." );
    431 				}
    432 			}
    433 		}
    434 		else	{
    435 			synchronized( _lock )	{
    436 				try	{
    437 					TimerTask	task = new TimerTask()	{
    438 						public void run()	{
    439 							synchronized( _lock )	{
    440 								_lock.notify();
    441 							}
    442 						}
    443 					};
    444 					_timer.schedule( task, wait );
    445 					_lastTask = task;
    446 					_lock.wait();
    447 				}
    448 				catch( InterruptedException ie )	{
    449 					Logger.debug( "[system.action] interrupted." );
    450 				}
    451 			}
    452 		}
    453
    454 		if( !isActive() && (_lastTask != null) )	{
    455 			synchronized( _lock )	{
    456 				if( !_activity && (_lastTask != null) )	{
    457 					_waitingActivate = true;
    458 					try	{
    459 						_lock.wait();
    460 						_lock.wait( 500 );
    461 					}
    462 					catch( InterruptedException ie )	{
    463 					}
    464 					_waitingActivate = false;
    465 				}
    466 			}
    467 		}
    468
    469 		_lastTask = null;
    470 		Logger.debug( "[system.controler] finish wait." );
    471 	}
    472
    473
    474 	/***
    475 	 * メニューバーを準備します。
    476 	 */
    477 	private void prepareMenuBar()
    478 	{
    479 		PekoSystem	system = PekoSystem.getInstance();
    480 		ResourceManager	resources = ResourceManager.getInstance();
    481
    482 		JMenuBar	menubar = new JMenuBar();
    483 		JMenu	menu = null;
    484 		JMenuItem	item = null;
    485
    486 		menu = new JMenu( (String)resources.getResource("peko.menu.system.menu-caption") );
    487 		menu.setMnemonic( 'S' );
    488 		menubar.add( menu );
    489
    490 		item = new JMenuItem( (String)resources.getResource("peko.menu.system.save") );
    491 		item.setEnabled( false );
    492 		item.setMnemonic( 'S' );
    493 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK) );
    494 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "showSaveDialog", true );
    495 		menu.add( item );
    496 		_saveMenu = item;
    497
    498 		item = new JMenuItem( (String)resources.getResource("peko.menu.system.load") );
    499 		item.setEnabled( false );
    500 		item.setMnemonic( 'O' );
    501 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK) );
    502 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "showLoadDialog", true );
    503 		menu.add( item );
    504 		_loadMenu = item;
    505
    506 		menu.addSeparator();
    507
    508 		item = new JMenuItem( (String)resources.getResource("peko.menu.system.return-title") );
    509 		item.setEnabled( false );
    510 		item.setMnemonic( 'T' );
    511 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK) );
    512 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "returnTitle", true );
    513 		menu.add( item );
    514 		_returnTileMenu = item;
    515
    516 		item = new JMenuItem( (String)resources.getResource("peko.menu.system.read-again") );
    517 		item.setEnabled( false );
    518 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_R, 0) );
    519 		item.setMnemonic( 'R' );
    520 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "showReadAgain" );
    521 		menu.add( item );
    522 		_readAgainMenu = item;
    523
    524 		menu.addSeparator();
    525
    526 		item = new JMenuItem( (String)resources.getResource("peko.menu.system.exit") );
    527 		item.setMnemonic( 'X' );
    528 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_MASK) );
    529 		GenericListener.connect( item, system, ActionListener.class, "actionPerformed", "exit" );
    530 		menu.add( item );
    531
    532
    533 		menu = new JMenu( (String)resources.getResource("peko.menu.config.menu-caption") );
    534 		menu.setMnemonic( 'C' );
    535 		menubar.add( menu );
    536
    537 		JMenu	submenu = new JMenu( (String)resources.getResource("peko.menu.config.playmode.menu-caption") );
    538 		submenu.setMnemonic( 'P' );
    539 		menu.add( submenu );
    540
    541 		ButtonGroup	group = new ButtonGroup();
    542 		item = new JRadioButtonMenuItem( (String)resources.getResource("peko.menu.config.playmode.normal") );
    543 		item.setMnemonic( 'N' );
    544 //		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK) );
    545 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "setPlayModeToNormal" );
    546 		group.add( item );
    547 		submenu.add( item );
    548 		_buttons[ ActionControler.PM_NORMAL ] = item;
    549
    550 		item = new JRadioButtonMenuItem( (String)resources.getResource("peko.menu.config.playmode.automatic") );
    551 		item.setMnemonic( 'A' );
    552 //		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK) );
    553 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "setPlayModeToAutomatic" );
    554 		group.add( item );
    555 		submenu.add( item );
    556 		_buttons[ ActionControler.PM_AUTOMATIC ] = item;
    557
    558 		item = new JRadioButtonMenuItem( (String)resources.getResource("peko.menu.config.playmode.skip") );
    559 		item.setMnemonic( 'S' );
    560 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_S, 0) );
    561 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "setPlayModeToSKip" );
    562 		group.add( item );
    563 		submenu.add( item );
    564 		_buttons[ ActionControler.PM_SKIP ] = item;
    565
    566 		menu.addSeparator();
    567
    568 		item = new JCheckBoxMenuItem( (String)resources.getResource("peko.menu.config.use-effect") );
    569 		item.setSelected( false );
    570 		item.setMnemonic( 'E' );
    571 		GenericListener.connect( item, this, ActionListener.class, "actionPerformed", "changeUsingEffect" );
    572 		menu.add( item );
    573 		_usingEffectMenu = item;
    574
    575
    576 		menu = new JMenu( (String)resources.getResource("peko.menu.help.menu-caption") );
    577 		menu.setMnemonic( 'H' );
    578 		menubar.add( menu );
    579
    580 		item = new JMenuItem( (String)resources.getResource("peko.menu.help.help-contents") );
    581 		item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0) );
    582 		item.setMnemonic( 'H' );
    583 		item.setEnabled( false );
    584 //		GenericListener.connect( item, system, ActionListener.class, "actionPerformed", "showGameVersionInfo" );
    585 		menu.add( item );
    586
    587 		item = new JMenuItem( (String)resources.getResource("peko.menu.help.version") );
    588 		item.setMnemonic( 'A' );
    589 		GenericListener.connect( item, system, ActionListener.class, "actionPerformed", "showGameVersionInfo" );
    590 		menu.add( item );
    591
    592 		menu.addSeparator();
    593
    594 		item = new JMenuItem( (String)resources.getResource("peko.menu.help.about-pvns") );
    595 		item.setMnemonic( 'P' );
    596 		GenericListener.connect( item, system, ActionListener.class, "actionPerformed", "showSystemVersionInfo" );
    597 		menu.add( item );
    598
    599
    600 		JFrame	mainWindow = system.getMainWindow();
    601 		mainWindow.setJMenuBar( menubar );
    602 		mainWindow.pack();
    603 		mainWindow.setResizable( false );
    604 	}
    605
    606
    607 //
    608 //	MouseListener の実装
    609 //
    610 	public void mousePressed( MouseEvent ev )
    611 	{
    612 	}
    613
    614 	public void mouseReleased( MouseEvent ev )
    615 	{
    616 	}
    617
    618 	public void mouseEntered( MouseEvent ev )
    619 	{
    620 	}
    621
    622 	public void mouseExited( MouseEvent ev )
    623 	{
    624 	}
    625
    626 	public void mouseClicked( MouseEvent ev )
    627 	{
    628 		int	code = ev.getModifiers();
    629 		if( isActive() && (code == MouseEvent.BUTTON1_MASK) )	{
    630 			start();
    631 		}
    632 		else if( (_playMode == ActionControler.PM_SKIP) && (code == MouseEvent.BUTTON3_MASK) )	{
    633 			setPlayModeToNormal();
    634 			return;
    635 		}
    636 		else if( _hiddenText )	{
    637 			CanvasManager	canvasManager = PekoSystem.getInstance().getCanvasManager();
    638 			canvasManager.hideTextCanvas();
    639 			setActive( true );
    640 		}
    641 	}
    642
    643
    644 //
    645 //	KeyListener の実装
    646 //
    647 	public void keyPressed( KeyEvent ev )
    648 	{
    649 		if( isActive() )	{
    650 			int	code = ev.getKeyCode();
    651 			if( _lastKeyCode == -1 )	{
    652 				_lastKeyCode = code;
    653 			}
    654 			else if( _lastKeyCode != code )	{
    655 				_lastKeyCode = -1;
    656 			}
    657 		}
    658 	}
    659
    660 	public void keyReleased( KeyEvent ev )
    661 	{
    662 		int	code = ev.getKeyCode();
    663 		if( code != _lastKeyCode )	{
    664 			_lastKeyCode = -1;
    665 			return;
    666 		}
    667
    668 		if( _hiddenText )	{
    669 			CanvasManager	canvasManager = PekoSystem.getInstance().getCanvasManager();
    670 			canvasManager.showTextCanvas();
    671 			_saveMenu.setEnabled( true );
    672 			_loadMenu.setEnabled( true );
    673 			_returnTileMenu.setEnabled( true );
    674 			_hiddenText = false;
    675 		}
    676 		else if( isActive() && (code == KeyEvent.VK_ENTER) )	{
    677 			start();
    678 		}
    679 		else if( (_playMode != ActionControler.PM_NORMAL) && (code == KeyEvent.VK_ESCAPE) )	{
    680 			setPlayModeToNormal();
    681 		}
    682 		else if( !_hiddenText && (code == KeyEvent.VK_SPACE) )	{
    683 			CanvasManager	canvasManager = PekoSystem.getInstance().getCanvasManager();
    684 			_saveMenu.setEnabled( false );
    685 			_loadMenu.setEnabled( false );
    686 			_returnTileMenu.setEnabled( false );
    687 			canvasManager.hideTextCanvas();
    688 			_hiddenText = true;
    689 		}
    690 		_lastKeyCode = -1;
    691 	}
    692
    693 	public void keyTyped( KeyEvent ev )
    694 	{
    695 	}
    696 }
    697
    698
    699
    700
    701 /***
    702  * テキストの履歴をブラウジングするコントローラです。
    703  */
    704 class TextHistoryControler	extends JDialog	{
    705
    706 	/***
    707 	 * serial version UID
    708 	 */
    709 	private static final long	serialVersionUID	= -5321584449609116120L;
    710
    711 	/***
    712 	 * 現在のインデックス
    713 	 */
    714 	private int	_index = 0;
    715
    716 	/***
    717 	 * キャンバスマネージャ
    718 	 */
    719 	private CanvasManager	_canvasManager = null;
    720
    721 	/***
    722 	 * 「前」ボタン
    723 	 */
    724 	private JButton	_previous = null;
    725
    726 	/***
    727 	 * 「次」ボタン
    728 	 */
    729 	private JButton	_next = null;
    730
    731
    732 	/***
    733 	 * <code>TextHistoryControler</code> のインスタンスを作成します。
    734 	 */
    735 	public TextHistoryControler()
    736 	{
    737 		super( PekoSystem.getInstance().getMainWindow(), true );
    738 		initialize();
    739 	}
    740
    741
    742 	/***
    743 	 * 初期化処理を実行します。
    744 	 */
    745 	private void initialize()
    746 	{
    747 		_canvasManager = PekoSystem.getInstance().getCanvasManager();
    748 		ClassLoader	cl = getClass().getClassLoader();
    749
    750 		getContentPane().setLayout( new java.awt.FlowLayout() );
    751 		JButton	button = new JButton();
    752 		button.setIcon( new ImageIcon(cl.getResource("left-arrow.png")) );
    753 		getContentPane().add( button );
    754 		GenericListener.connect( button, this, ActionListener.class, "actionPerformed", "previous" );
    755 		_previous = button;
    756 		button.setEnabled( (_canvasManager.getPageHistoryCount() >= 1) );
    757
    758 		button = new JButton();
    759 		button.setIcon( new ImageIcon(cl.getResource("right-arrow.png")) );
    760 		button.setEnabled( false );
    761 		getContentPane().add( button );
    762 		_next = button;
    763 		GenericListener.connect( button, this, ActionListener.class, "actionPerformed", "next" );
    764
    765 		pack();
    766 		setResizable( false );
    767 	}
    768
    769 	/***
    770 	 * 前のページを表示します。
    771 	 */
    772 	public void previous()
    773 	{
    774 		ResourceManager	resources = ResourceManager.getInstance();
    775 		_index++;
    776 		setTitle( ((MessageFormat)resources.getResource("peko.dialog.read-again.title-format")).format(new Object[]{String.valueOf(_index)}) );
    777 		_next.setEnabled( (_index > 1 ) );
    778 		if( _index == _canvasManager.getPageHistoryCount() )	{
    779 			_previous.setEnabled( false );
    780 		}
    781 		_previous.setEnabled( _canvasManager.readAgain(_index) );
    782 	}
    783
    784 	/***
    785 	 * 次のページを表示します。
    786 	 */
    787 	public void next()
    788 	{
    789 		ResourceManager	resources = ResourceManager.getInstance();
    790 		_index--;
    791 		setTitle( ((MessageFormat)resources.getResource("peko.dialog.read-again.title-format")).format(new Object[]{String.valueOf(_index)}) );
    792 		_previous.setEnabled( true );
    793 		if( _index == 1 )	{
    794 			_next.setEnabled( false );
    795 		}
    796 		_canvasManager.readAgain( _index );
    797 	}
    798
    799
    800 //
    801 //	JDialog の実装
    802 //
    803 	public void setVisible( boolean visible )
    804 	{
    805 		if( visible )	{
    806 			_index = 0;
    807 			if( _canvasManager.getPageHistoryCount() > 0 )	{
    808 				previous();
    809 			}
    810 		}
    811 		else	{
    812 			_canvasManager.returnCurrent();
    813 		}
    814 		super.setVisible( visible );
    815 	}
    816 }