1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 }