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: SelectCanvas.java,v 1.3 2005/07/24 20:55:57 ppoi Exp $
    18   */
    19  package tsukuba_bunko.peko.canvas.select;
    20
    21  import	java.awt.Dimension;
    22
    23  import	java.awt.event.KeyEvent;
    24  import	java.awt.event.KeyListener;
    25
    26  import	java.util.List;
    27  import	java.util.Map;
    28
    29  import	javax.swing.JComponent;
    30
    31  import	tsukuba_bunko.peko.ActionControler;
    32  import	tsukuba_bunko.peko.Logger;
    33  import	tsukuba_bunko.peko.PekoSystem;
    34
    35
    36  /***
    37   * 選択肢を表示するキャンバスです。
    38   * @author	$Author: ppoi $
    39   * @version	$Revision: 1.3 $
    40   */
    41  public class SelectCanvas	extends JComponent	implements KeyListener	{
    42
    43  	/***
    44  	 * serial version UID
    45  	 */
    46  	private static final long	serialVersionUID	= 103943516971774006L;
    47
    48  	/***
    49  	 * ボタンの位置：左寄せ
    50  	 */
    51  	public static final int	ALIGN_LEFT = 0;
    52
    53  	/***
    54  	 * ボタンの位置：中央
    55  	 */
    56  	public static final int	ALIGN_CENTER = 1;
    57
    58  	/***
    59  	 * ボタンの位置：右寄せ
    60  	 */
    61  	public static final int	ALIGN_RIGHT = 2;
    62
    63  	/***
    64  	 * ボタンの位置：上
    65  	 */
    66  	public static final int	VALIGN_TOP = 0;
    67
    68  	/***
    69  	 * ボタンの位置：中央
    70  	 */
    71  	public static final int	VALIGN_MIDDLE = 1;
    72
    73  	/***
    74  	 * ボタンの位置：下
    75  	 */
    76  	public static final int	VALIGN_BOTTOM = 2;
    77
    78
    79  	/***
    80  	 * 有効フラグ
    81  	 */
    82  	private boolean	_active = false;
    83
    84  	/***
    85  	 * 選択肢リスト
    86  	 */
    87  	private List	_buttons = null;
    88
    89  	/***
    90  	 * 選択された ID
    91  	 */
    92  	private String	_id = null;
    93
    94  	/***
    95  	 * 現在選択中のボタン
    96  	 */
    97  	private SelectItemButton	_selected = null;
    98
    99  	/***
    100 	 * 現在選択中のボタンのインデックス
    101 	 */
    102 	private int	_selectedIndex = -1;
    103
    104
    105 	/***
    106 	 * 最後に押されたキーのキーコード
    107 	 */
    108 	private int	_lastKeyCode = -1;
    109
    110
    111 	/***
    112 	 * 選択肢ボタンの配置位置
    113 	 */
    114 	private int	_align = SelectCanvas.ALIGN_CENTER;
    115
    116 	/***
    117 	 */
    118 	private int	_verticalAlign = SelectCanvas.VALIGN_TOP;
    119
    120 	/***
    121 	 * 選択肢の列数
    122 	 */
    123 	private int	_columns = 1;
    124
    125 	/***
    126 	 * 列間
    127 	 */
    128 	private int	_columnSpan = 20;
    129
    130 	/***
    131 	 * 行間
    132 	 */
    133 	private int	_rowSpan = 20;
    134
    135 	/***
    136 	 * 境界線とルートキャンバスの枠との間
    137 	 */
    138 	private int	_boundSpan = 20;
    139
    140 	/***
    141 	 * ボタンスタイルマップ
    142 	 */
    143 	private Map	_buttonStyle = null;
    144
    145 	/***
    146 	 * Dimension cache
    147 	 */
    148 	private Dimension	_dimensionCache = null;
    149
    150
    151 	/***
    152 	 * <code>SelectCanvas</code> のインスタンスを作成します。
    153 	 */
    154 	public SelectCanvas()
    155 	{
    156 		super();
    157 	}
    158
    159
    160 	/***
    161 	 * 選択肢ボタンの配置位置を設定します。設定した内容は、次回選択指表示時から反映されます。
    162 	 * @param	align	配置位置
    163 	 * @throws	IllegalArgumentException	align が {@link SelectCanvas#ALIGN_CENTER} または {@link SelectCanvas#ALIGN_LEFT} または {@link SelectCanvas#ALIGN_RIGHT} 以外の場合。
    164 	 */
    165 	public void setAlignment( int align )
    166 	{
    167 		if( (align == SelectCanvas.ALIGN_CENTER) || (align == SelectCanvas.ALIGN_LEFT) || (align == SelectCanvas.ALIGN_RIGHT) )	{
    168 			_align = align;
    169 		}
    170 		else	{
    171 			throw new IllegalArgumentException( "invalid alignment type is specified." );
    172 		}
    173 	}
    174
    175 	/***
    176 	 * 選択肢ボタンの配置位置を取得します。
    177 	 * @return	選択肢ボタンの配置位置
    178 	 */
    179 	public int getAlignment()
    180 	{
    181 		return _align;
    182 	}
    183
    184 	/***
    185 	 * 選択肢ボタンの垂直方向の配置位置を設定します。
    186 	 * @param	valign	配置位置
    187 	 * @throws	IllegalArgumentException	align が {@link SelectCanvas#VALIGN_TOP} または {@link SelectCanvas#VALIGN_MIDDLE} または {@link SelectCanvas#VALIGN_BOTTOM} 以外の場合。
    188 	 */
    189 	public void setVerticalAlignment( int valign )
    190 	{
    191 		if( (valign == SelectCanvas.ALIGN_CENTER) || (valign == SelectCanvas.ALIGN_LEFT) || (valign == SelectCanvas.ALIGN_RIGHT) )	{
    192 			_verticalAlign = valign;
    193 		}
    194 		else	{
    195 			throw new IllegalArgumentException( "invalid vertical alignment type is specified." );
    196 		}
    197 	}
    198
    199 	/***
    200 	 * 選択肢ボタンの垂直方向の配置位置を取得します。
    201 	 * @return	選択肢ボタンの配置位置
    202 	 */
    203 	public int getVericalAlignment()
    204 	{
    205 		return _verticalAlign;
    206 	}
    207
    208 	/***
    209 	 * 選択肢ボタンの列数を設定します。設定した内容は、次回選択指表示時から反映されます。
    210 	 * @param	columns 列数
    211 	 * @throws	IllegalArgumentException	<code>columns <= 0</code> の場合
    212 	 */
    213 	public void setColumns( int columns )
    214 	{
    215 		_columns = columns;
    216 	}
    217
    218 	/***
    219 	 * 選択肢ボタンの列数を取得します。
    220 	 * @return	選択肢ボタンの列数
    221 	 */
    222 	public int getColumns()
    223 	{
    224 		return _columns;
    225 	}
    226
    227 	/***
    228 	 * 列間を設定します。設定した内容は、次回選択指表示時から反映されます。
    229 	 * @param	span	列間の長さ
    230 	 */
    231 	public void setColumnSpan( int span )
    232 	{
    233 		_columnSpan = span;
    234 	}
    235
    236 	/***
    237 	 * 列間を取得します。
    238 	 * @return	列間の長さ
    239 	 */
    240 	public int getColumnSpan()
    241 	{
    242 		return _columnSpan;
    243 	}
    244
    245 	/***
    246 	 * 行間を設定します。設定した内容は、次回選択指表示時から反映されます。
    247 	 * @param	span	行間の長さ
    248 	 */
    249 	public void setRowSpan( int span )
    250 	{
    251 		_rowSpan = span;
    252 	}
    253
    254 	/***
    255 	 * 行間を取得します。
    256 	 * @return	行間の長さ
    257 	 */
    258 	public int getRowSpan()
    259 	{
    260 		return _rowSpan;
    261 	}
    262
    263 	/***
    264 	 * 選択肢領域の境界線とルートキャンバスの枠との間を設定します。設定した内容は、次回選択指表示時から反映されます。
    265 	 * @param	span	行間の長さ
    266 	 */
    267 	public void setBoundSpan( int span )
    268 	{
    269 		_boundSpan = span;
    270 	}
    271
    272 	/***
    273 	 * 選択肢領域の境界線とルートキャンバスの枠との間を取得します。
    274 	 * @return	行間の長さ
    275 	 */
    276 	public int getBoundSpan()
    277 	{
    278 		return _boundSpan;
    279 	}
    280
    281 	/***
    282 	 * 選択肢ボタンのスタイルを設定します。設定した内容は、次回選択指表示時から反映されます。
    283 	 * @param	styles	選択肢ボタンのスタイルマップ
    284 	 */
    285 	public void setButtonStyle( Map styles )
    286 	{
    287 		_buttonStyle = styles;
    288 	}
    289
    290 	/***
    291 	 * 選択肢ボタンのスタイルを取得します。
    292 	 * @return	選択肢ボタンのスタイル
    293 	 */
    294 	public Map getButtonStyle()
    295 	{
    296 		return _buttonStyle;
    297 	}
    298
    299 	/***
    300 	 * 選択肢を表示し、ユーザーが選択した選択肢の ID を取得します。
    301 	 * @param	selectItems	選択肢
    302 	 * @return	選択された選択肢の ID
    303 	 */
    304 	public String select( List selectItems )
    305 	{
    306 		return select( selectItems, -1 );
    307 	}
    308
    309 	/***
    310 	 * 選択肢を表示し、ユーザーが選択した選択肢の ID を取得します。
    311 	 * @param	selectItems	選択肢
    312 	 * @param	timeout	タイムアウトするまでの時間[ms]
    313 	 * @return	選択された選択肢の ID
    314 	 */
    315 	public String select( List selectItems, long timeout )
    316 	{
    317 		if( _buttonStyle == null )	{
    318 			throw new IllegalStateException( "button styles is not specified." );
    319 		}
    320
    321 		if( _active )	{
    322 			Logger.debug( "[canvas.select] already show selection." );
    323 			return null;
    324 		}
    325
    326 		synchronized( this )	{
    327 			_id = null;
    328
    329 			Dimension	canvasSize = getSize( _dimensionCache );
    330
    331 			int	size = selectItems.size();
    332 			int	buttonWidth = 320;
    333 			Integer	intValue = (Integer)_buttonStyle.get( SelectItemButton.STYLE_WIDTH );
    334 			if( intValue != null )	{
    335 				buttonWidth = intValue.intValue();
    336 			}
    337
    338 			setVisible( false );
    339
    340 			SelectItem	item = null;
    341 			SelectItemButton	button = null;
    342 			List	buttons = new java.util.ArrayList( size );
    343 			int	x = 0;
    344 			int	y = 0;
    345 			int	rowHeight = 0;
    346 			Dimension	buttonSize = new Dimension( 0, 0 );
    347 			for( int i = 0; i < size; ++i )	{
    348 				if( (i % _columns) == 0 )	{
    349 					y += rowHeight;
    350 					if( item != null )	{
    351 						y += _rowSpan;
    352 					}
    353 					x = 0;
    354 					rowHeight = 0;
    355 				}
    356 				else	{
    357 					x += (buttonSize.width + _columnSpan);
    358 				}
    359
    360 				item = (SelectItem)selectItems.get( i );
    361 				button = new SelectItemButton( this );
    362 				button.setSelectItem( item );
    363 				button.prepare( _buttonStyle );
    364 				buttons.add( button );
    365
    366 				add( button );
    367 				button.setLocation( x, y );
    368 				buttonSize = button.getSize( buttonSize );
    369 				if( buttonSize.height > rowHeight )	{
    370 					rowHeight = buttonSize.height;
    371 				}
    372 			}
    373
    374 			int	areaWidth = (buttonWidth * _columns) + (_columnSpan * (_columns - 1));
    375 			int	leftPosition = 0;
    376 			if( areaWidth > canvasSize.width )	{
    377 				leftPosition = 0;
    378 			}
    379 			else if( (areaWidth + _boundSpan) > canvasSize.width )	{
    380 				leftPosition = (canvasSize.width - areaWidth) / 2;
    381 			}
    382 			else if( _align == SelectCanvas.ALIGN_CENTER )	{
    383 				leftPosition = (canvasSize.width - areaWidth) / 2;
    384 			}
    385 			else if( _align == SelectCanvas.ALIGN_LEFT )	{
    386 				leftPosition = _boundSpan;
    387 			}
    388 			else if( _align == SelectCanvas.ALIGN_RIGHT )	{
    389 				leftPosition = canvasSize.width - areaWidth - _boundSpan;
    390 			}
    391
    392 			int	areaHeight = y + rowHeight;
    393 			int	topPosition = 0;
    394 			if( areaHeight > canvasSize.height )	{
    395 				topPosition = 0;
    396 			}
    397 			else if( (areaHeight + _boundSpan) > canvasSize.height )	{
    398 				topPosition = (canvasSize.height - areaHeight) / 2;
    399 			}
    400 			else if( _verticalAlign == SelectCanvas.VALIGN_TOP )	{
    401 				topPosition = _boundSpan;
    402 			}
    403 			else if( _verticalAlign == SelectCanvas.VALIGN_MIDDLE )	{
    404 				topPosition = (canvasSize.height - areaHeight) / 2;
    405 			}
    406 			else if( _verticalAlign == SelectCanvas.VALIGN_BOTTOM )	{
    407 				topPosition = canvasSize.height - areaHeight - _boundSpan;
    408 			}
    409 			setLocation( leftPosition, topPosition );
    410
    411 			_buttons = buttons;
    412 			_active = true;
    413
    414 			setVisible( true );
    415 		}
    416
    417 		Logger.debug( "[canvas.select] wait for selecting." );
    418 		ActionControler	controler = PekoSystem.getInstance().getActionControler();
    419 		if( timeout > 0 )	{
    420 			controler.stop( timeout );
    421 		}
    422 		else	{
    423 			controler.stop();
    424 		}
    425
    426 		synchronized( this )	{
    427 			int	size = _buttons.size();
    428 			for( int i = 0; i < size; ++i )	{
    429 				remove( (SelectItemButton)_buttons.get(i) );
    430 			}
    431 			_buttons.clear();
    432 			_buttons = null;
    433 		}
    434
    435 		Logger.debug( "[canvas.select] id: " + _id );
    436 		return _id;
    437 	}
    438
    439 	/***
    440 	 * 選択肢の選択待ちを解除します。
    441 	 */
    442 	public void cancel()
    443 	{
    444 		_active = false;
    445 		synchronized( this )	{
    446 			if( _buttons != null )	{
    447 				_id = null;
    448 				ActionControler	controler = PekoSystem.getInstance().getActionControler();
    449 				controler.start();
    450 				Logger.debug( "[cenvas.select] canceled." );
    451 			}
    452 		}
    453 	}
    454
    455
    456 //
    457 //	選択イベント処理
    458 //
    459 	/***
    460 	 * <code>button</code> が選択状態になりました。
    461 	 * @param	button	選択状態になった SelectItemButton インスタンス
    462 	 */
    463 	public void itemSelecting( SelectItemButton button )
    464 	{
    465 		SelectItemButton	old = _selected;
    466 		_selected = button;
    467 		if( (old != null) && (old != button) )	{
    468 			old.setSelected( false );
    469 		}
    470 		_selectedIndex = _buttons.indexOf( button );
    471 	}
    472
    473 	/***
    474 	 * <code>button</code> が非選択状態になりました
    475 	 * @param	button	非選択状態になった SelectItemButton インスタンス
    476 	 */
    477 	public void itemDeselected( SelectItemButton button )
    478 	{
    479 		if( _selected == button )	{
    480 			_selected = null;
    481 			_selectedIndex = -1;
    482 		}
    483 	}
    484
    485 	/***
    486 	 * <code>button</code> が選択されました。
    487 	 * @param	button	選択された SelectItemButton インスタンス
    488 	 */
    489 	public void itemSelected( SelectItemButton button )
    490 	{
    491 		if( _active )	{
    492 			synchronized( this )	{
    493 				if( _active )	{
    494 					_selected = null;
    495 					_selectedIndex = -1;
    496 					_id = button.getSelectItem().getID();
    497 					_active = false;
    498 					Logger.debug( "[canvas.select] selected: " + _id );
    499 					ActionControler	controler = PekoSystem.getInstance().getActionControler();
    500 					controler.start();
    501 				}
    502 			}
    503 		}
    504 	}
    505
    506
    507 //
    508 //	KeyListener の実装
    509 //
    510 	public void keyPressed( KeyEvent ev )
    511 	{
    512 		if( _active )	{
    513 			int	code = ev.getKeyCode();
    514 			if( _lastKeyCode == -1 )	{
    515 				_lastKeyCode = code;
    516 			}
    517 			else if( _lastKeyCode != code )	{
    518 				_lastKeyCode = -1;
    519 			}
    520
    521 			int	index = _selectedIndex;
    522 			int	size = _buttons.size();
    523
    524 			if( code == KeyEvent.VK_DOWN )	{
    525 				index = (index + 1) % size;
    526 			}
    527 			else if( (code == KeyEvent.VK_RIGHT) && (_columns > 1) )	{
    528 				index = (index + 1) % size;
    529 			}
    530 			else if( code == KeyEvent.VK_UP )	 {
    531 				index--;
    532 				if( index < 0 )	{
    533 					index = _buttons.size() -1 ;
    534 				}
    535 			}
    536 			else if( (code == KeyEvent.VK_LEFT) && (_columns > 1) )	{
    537 				index--;
    538 				if( index < 0 )	{
    539 					index = _buttons.size() -1 ;
    540 				}
    541 			}
    542 			else	{
    543 				return;
    544 			}
    545 			SelectItemButton	button = (SelectItemButton)_buttons.get( index );
    546 			button.setSelected( true );
    547 		}
    548 	}
    549
    550 	public void keyReleased( KeyEvent ev )
    551 	{
    552 		if( !_active || (_buttons == null) )	{
    553 			return;
    554 		}
    555
    556 		int	code = ev.getKeyCode();
    557 		if( code != _lastKeyCode )	{
    558 			_lastKeyCode = -1;
    559 			return;
    560 		}
    561
    562 		if( (code == KeyEvent.VK_ENTER) && (_selected != null) )	{
    563 			itemSelected( _selected );
    564 		}
    565 		_lastKeyCode = -1;
    566 	}
    567
    568 	public void keyTyped( KeyEvent ev )
    569 	{
    570 	}
    571 }