OSDN Git Service

Merge branch 'Branch_release-'
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / summary / VillageDigest.java
1 /*
2  * Village digest GUI
3  *
4  * License : The MIT License
5  * Copyright(c) 2009 olyutorskii
6  */
7
8 package jp.sfjp.jindolf.summary;
9
10 import java.awt.Container;
11 import java.awt.Dimension;
12 import java.awt.EventQueue;
13 import java.awt.Frame;
14 import java.awt.GridBagConstraints;
15 import java.awt.GridBagLayout;
16 import java.awt.Image;
17 import java.awt.Insets;
18 import java.awt.LayoutManager;
19 import java.awt.Rectangle;
20 import java.awt.event.ActionEvent;
21 import java.awt.event.ActionListener;
22 import java.awt.event.ItemEvent;
23 import java.awt.event.ItemListener;
24 import java.awt.event.WindowAdapter;
25 import java.awt.event.WindowEvent;
26 import java.text.DateFormat;
27 import java.util.Date;
28 import java.util.List;
29 import javax.swing.BorderFactory;
30 import javax.swing.DefaultComboBoxModel;
31 import javax.swing.ImageIcon;
32 import javax.swing.JButton;
33 import javax.swing.JComboBox;
34 import javax.swing.JComponent;
35 import javax.swing.JDialog;
36 import javax.swing.JLabel;
37 import javax.swing.JPanel;
38 import javax.swing.JPopupMenu;
39 import javax.swing.JScrollPane;
40 import javax.swing.JTabbedPane;
41 import javax.swing.JTextArea;
42 import javax.swing.JViewport;
43 import javax.swing.border.Border;
44 import jp.sfjp.jindolf.data.Avatar;
45 import jp.sfjp.jindolf.data.Period;
46 import jp.sfjp.jindolf.data.Player;
47 import jp.sfjp.jindolf.data.Village;
48 import jp.sfjp.jindolf.dxchg.ClipboardAction;
49 import jp.sfjp.jindolf.dxchg.FaceIconSet;
50 import jp.sfjp.jindolf.dxchg.TextPopup;
51 import jp.sfjp.jindolf.dxchg.WebButton;
52 import jp.sfjp.jindolf.dxchg.WolfBBS;
53 import jp.sfjp.jindolf.util.GUIUtils;
54 import jp.sfjp.jindolf.util.Monodizer;
55 import jp.sourceforge.jindolf.corelib.GameRole;
56 import jp.sourceforge.jindolf.corelib.Team;
57
58 /**
59  * 決着のついた村のダイジェストを表示する。
60  */
61 @SuppressWarnings("serial")
62 public class VillageDigest
63         extends JDialog
64         implements ActionListener,
65                    ItemListener {
66
67     private static final String ITEMDELIM = " : ";
68
69
70     private final JComponent summaryPanel = buildSummaryPanel();
71
72     private final JLabel faceLabel = new JLabel();
73     private final ImageIcon faceIcon = new ImageIcon();
74     private final JComboBox<Avatar> playerBox = new JComboBox<>();
75     private final DefaultComboBoxModel<Avatar> playerListModel =
76             new DefaultComboBoxModel<>();
77     private final JButton prevPlayer = new JButton("↑");
78     private final JButton nextPlayer = new JButton("↓");
79     private final JLabel roleLabel = new JLabel();
80     private final JLabel destinyLabel = new JLabel();
81     private final JLabel specialSkillLabel = new JLabel();
82     private final JLabel entryLabel = new JLabel();
83     private final JLabel idLabel = new JLabel();
84     private final WebButton urlLine = new WebButton();
85     private final JComponent playerPanel = buildPlayerPanel();
86
87     private final JComboBox<FaceIconSet> iconSetBox = new JComboBox<>();
88     private final DefaultComboBoxModel<FaceIconSet> iconSetListModel =
89             new DefaultComboBoxModel<>();
90     private final JLabel authorLabel = new JLabel();
91     private final JLabel authorUrlLabel = new JLabel();
92     private final WebButton iconCatalog = new WebButton();
93     private final JButton genCastTableButton =
94             new JButton("キャスト表Wiki生成");
95     private final JButton copyClipButton =
96             new JButton("クリップボードにコピー");
97     private final JTextArea templateArea = new JTextArea();
98     private final JButton voteButton = new JButton("投票Wiki生成");
99     private final JButton vlgWikiButton = new JButton("村詳細Wiki生成");
100     private final JComponent clipboardPanel = buildClipboardPanel();
101
102     private final JButton closeButton = new JButton("閉じる");
103
104     private Village village;
105
106     private GameSummary gameSummary;
107
108
109     /**
110      * コンストラクタ。
111      * @param owner 親フレーム
112      */
113     public VillageDigest(Frame owner){
114         super(owner);
115         setModal(true);
116
117         GUIUtils.modifyWindowAttributes(this, true, false, true);
118
119         setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
120         addWindowListener(new WindowAdapter(){
121             @Override
122             public void windowClosing(WindowEvent event){
123                 actionClose();
124                 return;
125             }
126         });
127
128         this.faceLabel.setIcon(this.faceIcon);
129
130         this.playerBox.setModel(this.playerListModel);
131         this.playerBox.addItemListener(this);
132
133         this.prevPlayer.setMargin(new Insets(1, 1, 1, 1));
134         this.prevPlayer.addActionListener(this);
135         this.prevPlayer.setToolTipText("前のプレイヤー");
136
137         this.nextPlayer.setMargin(new Insets(1, 1, 1, 1));
138         this.nextPlayer.addActionListener(this);
139         this.nextPlayer.setToolTipText("次のプレイヤー");
140
141         this.iconSetBox.setModel(this.iconSetListModel);
142         this.iconSetBox.addItemListener(this);
143         for(FaceIconSet iconSet : WolfBBS.getFaceIconSetList()){
144             this.iconSetListModel.addElement(iconSet);
145         }
146
147         this.iconCatalog.setURLText(
148                 "http://wolfbbs.jp/"
149                 +"%A4%DE%A4%C8%A4%E1%A5%B5%A5%A4%A5%C8%A4%C7"
150                 +"%CD%F8%CD%D1%B2%C4%C7%BD%A4%CA%A5%A2%A5%A4"
151                 +"%A5%B3%A5%F3%B2%E8%C1%FC.html");
152         this.iconCatalog.setCaption("顔アイコン見本ページ");
153
154         this.templateArea.setEditable(true);
155         this.templateArea.setLineWrap(true);
156         Monodizer.monodize(this.templateArea);
157         JPopupMenu popup = new TextPopup();
158         this.templateArea.setComponentPopupMenu(popup);
159
160         this.genCastTableButton.addActionListener(this);
161         this.voteButton.addActionListener(this);
162         this.vlgWikiButton.addActionListener(this);
163         this.copyClipButton.addActionListener(this);
164
165         this.closeButton.addActionListener(this);
166
167         Monodizer.monodize(this.idLabel);
168         Monodizer.monodize(this.authorUrlLabel);
169
170         Container content = getContentPane();
171         design(content);
172
173         return;
174     }
175
176
177     /**
178      * キャプション付き項目をコンテナに追加。
179      * @param container コンテナ
180      * @param caption 項目キャプション名
181      * @param delimiter デリミタ文字
182      * @param item 項目アイテム
183      */
184     private static void addCaptionedItem(Container container,
185                                            CharSequence caption,
186                                            CharSequence delimiter,
187                                            Object item ){
188         LayoutManager layout = container.getLayout();
189         if( ! (layout instanceof GridBagLayout) ){
190             throw new IllegalArgumentException();
191         }
192
193         JLabel captionLabel   = new JLabel(caption.toString());
194         JLabel delimiterLabel = new JLabel(delimiter.toString());
195         JComponent itemComp;
196         if(item instanceof JComponent){
197             itemComp = (JComponent) item;
198         }else{
199             itemComp = new JLabel(item.toString());
200         }
201
202         GridBagConstraints constraints = new GridBagConstraints();
203
204         constraints.weightx = 0.0;
205         constraints.weighty = 0.0;
206         constraints.fill    = GridBagConstraints.NONE;
207         constraints.insets  = new Insets(2, 2, 2, 2);
208
209         constraints.gridwidth = 1;
210         constraints.anchor    = GridBagConstraints.NORTHEAST;
211         container.add(captionLabel, constraints);
212         container.add(delimiterLabel, constraints);
213
214         constraints.weightx = 1.0;
215         constraints.gridwidth = GridBagConstraints.REMAINDER;
216         constraints.anchor    = GridBagConstraints.NORTHWEST;
217         container.add(itemComp, constraints);
218
219         return;
220     }
221
222     /**
223      * キャプション付き項目をコンテナに追加。
224      * @param container コンテナ
225      * @param caption 項目キャプション名
226      * @param item 項目アイテム
227      */
228     private static void addCaptionedItem(Container container,
229                                            CharSequence caption,
230                                            Object item ){
231         addCaptionedItem(container, caption, ITEMDELIM, item);
232         return;
233     }
234
235     /**
236      * レイアウトの最後に詰め物をする。
237      * @param container コンテナ
238      */
239     private static void addFatPad(Container container){
240         LayoutManager layout = container.getLayout();
241         if( ! (layout instanceof GridBagLayout) ){
242             throw new IllegalArgumentException();
243         }
244
245         JComponent pad = new JPanel();
246
247         GridBagConstraints constraints = new GridBagConstraints();
248         constraints.weightx = 1.0;
249         constraints.weighty = 1.0;
250         constraints.fill    = GridBagConstraints.BOTH;
251         constraints.gridwidth = GridBagConstraints.REMAINDER;
252         container.add(pad, constraints);
253
254         return;
255     }
256
257     /**
258      * GridBagLayoutでレイアウトする空コンポーネントを生成する。
259      * @return 空コンポーネント
260      */
261     private static JComponent createGridBagComponent(){
262         JComponent result = new JPanel();
263         LayoutManager layout = new GridBagLayout();
264         result.setLayout(layout);
265         return result;
266     }
267
268     /**
269      * 村サマリ画面の生成。
270      * @return 村サマリ画面
271      */
272     private JComponent buildSummaryPanel(){
273         JComponent result = createGridBagComponent();
274
275         Border border = BorderFactory.createEmptyBorder(5, 5, 5, 5);
276         result.setBorder(border);
277
278         return result;
279     }
280
281     /**
282      * プレイヤーサマリ画面の生成。
283      * @return プレイヤーサマリ画面
284      */
285     private JComponent buildPlayerPanel(){
286         JComponent result = createGridBagComponent();
287         GridBagConstraints constraints = new GridBagConstraints();
288
289         constraints.weightx = 0.0;
290         constraints.weighty = 0.0;
291         constraints.fill    = GridBagConstraints.NONE;
292         constraints.anchor  = GridBagConstraints.NORTHEAST;
293         constraints.insets  = new Insets(2, 2, 2, 2);
294         result.add(this.faceLabel, constraints);
295
296         result.add(new JLabel(ITEMDELIM), constraints);
297
298         constraints.anchor  = GridBagConstraints.NORTHWEST;
299         result.add(this.playerBox, constraints);
300         result.add(this.prevPlayer, constraints);
301         constraints.gridwidth = GridBagConstraints.REMAINDER;
302         result.add(this.nextPlayer, constraints);
303
304         addCaptionedItem(result, "役職",      this.roleLabel);
305         addCaptionedItem(result, "運命",      this.destinyLabel);
306         addCaptionedItem(result, "特殊技能",  this.specialSkillLabel);
307         addCaptionedItem(result, "エントリ#", this.entryLabel);
308         addCaptionedItem(result, "ID",        this.idLabel);
309         addCaptionedItem(result, "URL",       this.urlLine);
310
311         constraints.weightx = 1.0;
312         constraints.weighty = 1.0;
313         constraints.fill    = GridBagConstraints.BOTH;
314         constraints.gridwidth = GridBagConstraints.REMAINDER;
315         result.add(new JPanel(), constraints);
316
317         Border border = BorderFactory.createEmptyBorder(5, 5, 5, 5);
318         result.setBorder(border);
319
320         return result;
321     }
322
323     /**
324      * キャスト表生成画面を生成する。
325      * @return キャスト表生成画面
326      */
327     private JComponent buildCastPanel(){
328         JComponent result = createGridBagComponent();
329         GridBagConstraints constraints = new GridBagConstraints();
330
331         constraints.anchor  = GridBagConstraints.NORTHEAST;
332         constraints.gridwidth = GridBagConstraints.REMAINDER;
333         constraints.insets  = new Insets(2, 2, 2, 2);
334         result.add(this.iconCatalog, constraints);
335
336         addCaptionedItem(result, "顔アイコンセットを選択", this.iconSetBox);
337         addCaptionedItem(result, "作者", this.authorLabel);
338         addCaptionedItem(result, "URL", this.authorUrlLabel);
339
340         constraints.weightx = 1.0;
341         constraints.weighty = 0.0;
342         constraints.fill    = GridBagConstraints.NONE;
343         constraints.insets  = new Insets(2, 2, 2, 2);
344         constraints.anchor  = GridBagConstraints.NORTHEAST;
345         constraints.gridwidth = GridBagConstraints.REMAINDER;
346         result.add(this.genCastTableButton, constraints);
347
348         Border border = BorderFactory.createTitledBorder("キャスト表Wiki生成");
349         result.setBorder(border);
350
351         return result;
352     }
353
354     /**
355      * 投票Box生成画面を生成する。
356      * @return 投票Box生成画面
357      */
358     private JComponent buildVotePanel(){
359         JComponent result = createGridBagComponent();
360         GridBagConstraints constraints = new GridBagConstraints();
361
362         constraints.weightx = 1.0;
363         constraints.weighty = 0.0;
364         constraints.fill    = GridBagConstraints.NONE;
365         constraints.anchor  = GridBagConstraints.NORTHEAST;
366         constraints.gridwidth = GridBagConstraints.REMAINDER;
367         constraints.insets  = new Insets(2, 2, 2, 2);
368         result.add(this.voteButton, constraints);
369
370         Border border = BorderFactory.createTitledBorder("投票Wiki生成");
371         result.setBorder(border);
372
373         return result;
374     }
375
376     /**
377      * 村詳細Wiki生成画面を生成する。
378      * @return 村詳細Wiki生成画面
379      */
380     private JComponent buildVillageWikiPanel(){
381         JComponent result = createGridBagComponent();
382         GridBagConstraints constraints = new GridBagConstraints();
383
384         constraints.weightx = 1.0;
385         constraints.weighty = 0.0;
386         constraints.fill    = GridBagConstraints.NONE;
387         constraints.anchor  = GridBagConstraints.NORTHEAST;
388         constraints.gridwidth = GridBagConstraints.REMAINDER;
389         constraints.insets  = new Insets(2, 2, 2, 2);
390         result.add(this.vlgWikiButton, constraints);
391
392         Border border = BorderFactory.createTitledBorder("村詳細Wiki生成");
393         result.setBorder(border);
394
395         return result;
396     }
397
398     /**
399      * Wikiテキスト領域GUIの生成。
400      * @return Wikiテキスト領域GUI
401      */
402     private JComponent buildClipText(){
403         JComponent result = createGridBagComponent();
404         GridBagConstraints constraints = new GridBagConstraints();
405
406         Border border;
407
408         constraints.insets = new Insets(2, 2, 2, 2);
409
410         constraints.weightx   = 0.0;
411         constraints.weighty   = 0.0;
412         constraints.fill      = GridBagConstraints.NONE;
413         constraints.anchor    = GridBagConstraints.NORTHEAST;
414         constraints.gridwidth = GridBagConstraints.REMAINDER;
415         result.add(this.copyClipButton, constraints);
416
417         border = BorderFactory.createEmptyBorder(2, 2, 2, 2);
418         this.templateArea.setBorder(border);
419         JScrollPane scroller = new JScrollPane();
420         JViewport viewPort = scroller.getViewport();
421         viewPort.setView(this.templateArea);
422         scroller.setHorizontalScrollBarPolicy(
423                 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
424         );
425         scroller.setMinimumSize(new Dimension(10, 50));
426
427         constraints.weightx = 1.0;
428         constraints.weighty = 1.0;
429         constraints.fill    = GridBagConstraints.BOTH;
430         constraints.gridwidth = GridBagConstraints.REMAINDER;
431         result.add(scroller, constraints);
432
433         border = BorderFactory.createTitledBorder("PukiWikiテキスト");
434         result.setBorder(border);
435
436         return result;
437     }
438
439     /**
440      * テンプレート生成画面を生成する。
441      * @return テンプレート生成画面
442      */
443     private JComponent buildClipboardPanel(){
444         JComponent result = createGridBagComponent();
445         GridBagConstraints constraints = new GridBagConstraints();
446
447         constraints.insets = new Insets(3, 3, 3, 3);
448
449         constraints.weightx = 1.0;
450         constraints.weighty = 0.0;
451         constraints.fill    = GridBagConstraints.HORIZONTAL;
452         constraints.anchor  = GridBagConstraints.NORTHWEST;
453         constraints.gridwidth = GridBagConstraints.REMAINDER;
454
455         JComponent castPanel = buildCastPanel();
456         result.add(castPanel, constraints);
457
458         JComponent vlgWikiPanel = buildVillageWikiPanel();
459         result.add(vlgWikiPanel, constraints);
460
461         JComponent votePanel = buildVotePanel();
462         result.add(votePanel, constraints);
463
464         constraints.fill    = GridBagConstraints.NONE;
465         constraints.anchor  = GridBagConstraints.CENTER;
466         result.add(new JLabel("↓↓↓"), constraints);
467         constraints.fill    = GridBagConstraints.HORIZONTAL;
468         constraints.anchor  = GridBagConstraints.NORTHWEST;
469
470         constraints.weightx = 1.0;
471         constraints.weighty = 1.0;
472         constraints.fill    = GridBagConstraints.BOTH;
473         constraints.gridwidth = GridBagConstraints.REMAINDER;
474         JComponent clipText = buildClipText();
475         result.add(clipText, constraints);
476
477         return result;
478     }
479
480     /**
481      * 画面レイアウトを行う。
482      * @param container コンテナ
483      */
484     private void design(Container container){
485         LayoutManager layout = new GridBagLayout();
486         GridBagConstraints constraints = new GridBagConstraints();
487
488         container.setLayout(layout);
489
490         JScrollPane scroller1 = new JScrollPane();
491         scroller1.getVerticalScrollBar().setUnitIncrement(15);
492         scroller1.getHorizontalScrollBar().setUnitIncrement(15);
493         JViewport viewPort1 = scroller1.getViewport();
494         viewPort1.setView(this.summaryPanel);
495
496         JScrollPane scroller2 = new JScrollPane();
497         scroller2.getVerticalScrollBar().setUnitIncrement(15);
498         scroller2.getHorizontalScrollBar().setUnitIncrement(15);
499         JViewport viewPort2 = scroller2.getViewport();
500         viewPort2.setView(this.playerPanel);
501
502         JTabbedPane tabComp = new JTabbedPane();
503         tabComp.add("村詳細", scroller1);
504         tabComp.add("プレイヤー詳細", scroller2);
505         tabComp.add("まとめサイト用Wiki生成", this.clipboardPanel);
506
507         constraints.weightx   = 1.0;
508         constraints.weighty   = 1.0;
509         constraints.fill      = GridBagConstraints.BOTH;
510         constraints.anchor    = GridBagConstraints.NORTHWEST;
511         constraints.gridwidth = GridBagConstraints.REMAINDER;
512         container.add(tabComp, constraints);
513
514         constraints.insets = new Insets(3, 3, 3, 3);
515         constraints.weightx = 0.0;
516         constraints.weighty = 0.0;
517         constraints.fill    = GridBagConstraints.NONE;
518         constraints.anchor  = GridBagConstraints.SOUTHEAST;
519         container.add(this.closeButton, constraints);
520
521         return;
522     }
523
524     /**
525      * このモーダルダイアログを閉じる。
526      */
527     private void actionClose(){
528         setVisible(false);
529         dispose();
530         return;
531     }
532
533     /**
534      * 村を設定する。
535      * @param village 村
536      */
537     public void setVillage(Village village){
538         clear();
539
540         this.village = village;
541         if(village == null) return;
542
543         this.gameSummary = new GameSummary(this.village);
544
545         updateSummary();
546
547         for(Player player : this.gameSummary.getPlayerList()){
548             Avatar avatar = player.getAvatar();
549             this.playerListModel.addElement(avatar);
550         }
551
552         if(this.playerListModel.getSize() >= 2){ // 強制イベント発生
553             Object player2nd = this.playerListModel.getElementAt(1);
554             this.playerListModel.setSelectedItem(player2nd);
555             Object player1st = this.playerListModel.getElementAt(0);
556             this.playerListModel.setSelectedItem(player1st);
557         }
558
559         return;
560     }
561
562     /**
563      * 村詳細画面の更新。
564      */
565     private void updateSummary(){
566         String villageName = this.village.getVillageFullName();
567
568         Team winnerTeam = this.gameSummary.getWinnerTeam();
569         String wonTeam = winnerTeam.getTeamName();
570
571         int avatarNum = this.gameSummary.countAvatarNum();
572         String totalMember = "ゲルト + " + (avatarNum - 1) + "名 = "
573                             + avatarNum + "名";
574
575         JComponent roleDetail = createGridBagComponent();
576         for(GameRole role : GameRole.values()){
577             List<Player> players = this.gameSummary.getRoledPlayerList(role);
578             if(players.size() <= 0) continue;
579             String roleName = role.getRoleName();
580             addCaptionedItem(roleDetail, roleName, " × ", players.size());
581         }
582
583         String suddenDeath = this.gameSummary.countSuddenDeath() + "名";
584
585         DateFormat dform =
586                 DateFormat.getDateTimeInstance(DateFormat.FULL,
587                                                DateFormat.FULL);
588         Date date;
589         date = this.gameSummary.get1stTalkDate();
590         String talk1st = dform.format(date);
591         date = this.gameSummary.getLastTalkDate();
592         String talkLast = dform.format(date);
593
594         int limitHour   = this.village.getLimitHour();
595         int limitMinute = this.village.getLimitMinute();
596         StringBuilder limit = new StringBuilder();
597         if(limitHour < 10) limit.append('0');
598         limit.append(limitHour).append(':');
599         if(limitMinute < 10) limit.append('0');
600         limit.append(limitMinute);
601
602         JComponent transition = createGridBagComponent();
603         for(int day = 1; day < this.village.getPeriodSize(); day++){
604             List<Player> players = this.gameSummary.getSurvivorList(day);
605             CharSequence roleSeq =
606                     GameSummary.getRoleBalanceSequence(players);
607             String daySeq;
608             Period period = this.village.getPeriod(day);
609             daySeq = period.getCaption();
610             addCaptionedItem(transition, daySeq, roleSeq);
611         }
612
613         StringBuilder schedule = new StringBuilder();
614         int progressDays = this.village.getProgressDays();
615         schedule.append("プロローグ + ")
616                 .append(progressDays)
617                 .append("日 + エピローグ");
618
619         CharSequence exeInfo = this.gameSummary.dumpExecutionInfo();
620         CharSequence eatInfo = this.gameSummary.dumpAssaultInfo();
621         CharSequence scoreSeer = this.gameSummary.dumpSeerActivity();
622         CharSequence scoreHunter = this.gameSummary.dumpHunterActivity();
623
624         this.summaryPanel.removeAll();
625
626         addCaptionedItem(this.summaryPanel, "村名",     villageName);
627         addCaptionedItem(this.summaryPanel, "勝者",     wonTeam);
628         addCaptionedItem(this.summaryPanel, "所要日数", schedule);
629         addCaptionedItem(this.summaryPanel, "更新時刻", limit);
630         addCaptionedItem(this.summaryPanel, "発言開始", talk1st);
631         addCaptionedItem(this.summaryPanel, "最終発言", talkLast);
632         addCaptionedItem(this.summaryPanel, "参加人数", totalMember);
633         addCaptionedItem(this.summaryPanel, "役職内訳", roleDetail);
634         addCaptionedItem(this.summaryPanel, "処刑内訳", exeInfo);
635         addCaptionedItem(this.summaryPanel, "襲撃内訳", eatInfo);
636         addCaptionedItem(this.summaryPanel, "突然死",   suddenDeath);
637         addCaptionedItem(this.summaryPanel, "人口推移", transition);
638         addCaptionedItem(this.summaryPanel, "占成績", scoreSeer);
639         addCaptionedItem(this.summaryPanel, "狩成績", scoreHunter);
640
641         addFatPad(this.summaryPanel);
642
643         return;
644     }
645
646     /**
647      * アクションイベントの振り分け。
648      * @param event アクションイベント
649      */
650     @Override
651     public void actionPerformed(ActionEvent event){
652         Object source = event.getSource();
653
654         if(source == this.closeButton){
655             actionClose();
656         }else if(source == this.copyClipButton){
657             actionCopyToClipboard();
658         }else if(source == this.genCastTableButton){
659             actionGenCastTable();
660         }else if(source == this.voteButton){
661             actionGenVoteBox();
662         }else if(source == this.vlgWikiButton){
663             actionGenVillageWiki();
664         }else if(source == this.prevPlayer){
665             int index = this.playerBox.getSelectedIndex();
666             if(index <= 0) return;
667             index--;
668             this.playerBox.setSelectedIndex(index);
669         }else if(source == this.nextPlayer){
670             int index = this.playerBox.getSelectedIndex();
671             int playerNum = this.playerBox.getItemCount();
672             if(index >= playerNum - 1) return;
673             index++;
674             this.playerBox.setSelectedIndex(index);
675         }
676
677         return;
678     }
679
680     /**
681      * キャスト表Wikiデータの生成を行う。
682      */
683     private void actionGenCastTable(){
684         Object selected = this.iconSetListModel.getSelectedItem();
685         if( ! (selected instanceof FaceIconSet) ) return;
686         FaceIconSet iconSet = (FaceIconSet) selected;
687
688         CharSequence wikiText = this.gameSummary.dumpCastingBoard(iconSet);
689
690         putWikiText(wikiText);
691
692         return;
693     }
694
695     /**
696      * 投票Boxを生成する。
697      */
698     private void actionGenVoteBox(){
699         CharSequence wikiText = this.gameSummary.dumpVoteBox();
700         putWikiText(wikiText);
701         return;
702     }
703
704     /**
705      * 村詳細Wikiを生成する。
706      */
707     private void actionGenVillageWiki(){
708         CharSequence wikiText = this.gameSummary.dumpVillageWiki();
709         putWikiText(wikiText);
710         return;
711     }
712
713     /**
714      * Wikiテキストをテキストボックスに出力する。
715      * スクロール位置は一番上に。
716      * @param wikiText Wikiテキスト
717      */
718     private void putWikiText(CharSequence wikiText){
719         this.templateArea.setText(wikiText.toString());
720         // 最上部へスクロールアップ
721         EventQueue.invokeLater(new Runnable(){
722             @Override
723             public void run(){
724                 JTextArea area = VillageDigest.this.templateArea;
725                 area.scrollRectToVisible(new Rectangle());
726             }
727         });
728         // TODO あらかじめテキストを全選択させておきたい
729         return;
730     }
731
732     /**
733      * Wiki文字列をクリップボードへコピーする。
734      */
735     private void actionCopyToClipboard(){
736         CharSequence text = this.templateArea.getText();
737         ClipboardAction.copyToClipboard(text);
738         return;
739     }
740
741     /**
742      * プレイヤーの選択操作。
743      * @param avatar 選択されたAvatar
744      */
745     private void selectPlayer(Avatar avatar){
746         if(avatar == this.playerBox.getItemAt(0)){
747             this.prevPlayer.setEnabled(false);
748         }else{
749             this.prevPlayer.setEnabled(true);
750         }
751
752         int playerNum = this.playerBox.getItemCount();
753         if(avatar == this.playerBox.getItemAt(playerNum - 1)){
754             this.nextPlayer.setEnabled(false);
755         }else{
756             this.nextPlayer.setEnabled(true);
757         }
758
759         Image image = this.village.getAvatarFaceImage(avatar);
760         this.faceIcon.setImage(image);
761         this.faceLabel.setIcon(null);          // なぜかこれが必要
762         this.faceLabel.setIcon(this.faceIcon);
763
764         Player player = this.gameSummary.getPlayer(avatar);
765
766         GameRole role = player.getRole();
767         this.roleLabel.setText(role.getRoleName());
768
769         String destinyMessage = player.getDestinyMessage();
770         this.destinyLabel.setText(destinyMessage);
771
772         CharSequence specialSkill = "";
773         switch(role){
774         case SEER:
775             specialSkill = this.gameSummary.dumpSeerActivity();
776             break;
777         case HUNTER:
778             specialSkill = this.gameSummary.dumpHunterActivity();
779             break;
780         default:
781             break;
782         }
783         this.specialSkillLabel.setText(specialSkill.toString());
784
785         this.entryLabel.setText(String.valueOf(player.getEntryNo()));
786
787         String userId = player.getIdName();
788         this.idLabel.setText(userId);
789
790         String urlText = player.getUrlText();
791         String caption = urlText;
792
793         if(urlText == null || urlText.length() <= 0){
794             urlText = WolfBBS.encodeURLFromId(userId);
795             caption = "もしかして " + urlText;
796         }
797
798         this.urlLine.setURLText(urlText);
799         this.urlLine.setCaption(caption);
800
801         return;
802     }
803
804     /**
805      * 顔アイコンセットの選択操作。
806      * @param iconSet 顔アイコンセット
807      */
808     private void selectIconSet(FaceIconSet iconSet){
809         String author  = iconSet.getAuthor();
810         String urlText = iconSet.getUrlText();
811         this.authorLabel   .setText(author + "氏");
812         this.authorUrlLabel.setText(urlText);
813         return;
814     }
815
816     /**
817      * コンボボックス操作の受信。
818      * @param event コンボボックス操作イベント
819      */
820     @Override
821     public void itemStateChanged(ItemEvent event){
822         int state = event.getStateChange();
823         if(state != ItemEvent.SELECTED) return;
824
825         Object source = event.getSource();
826         Object item = event.getItem();
827         if(item == null) return;
828
829         if(source == this.playerBox){
830             if( ! (item instanceof Avatar) ) return;
831             Avatar avatar = (Avatar) item;
832             selectPlayer(avatar);
833         }else if(source == this.iconSetBox){
834             if( ! (item instanceof FaceIconSet) ) return;
835             FaceIconSet iconSet = (FaceIconSet) item;
836             selectIconSet(iconSet);
837         }
838
839         return;
840     }
841
842     /**
843      * 表示内容をクリアする。
844      */
845     private void clear(){
846         this.templateArea.setText("");
847         this.playerListModel.removeAllElements();
848         return;
849     }
850
851     // TODO ハムスター対応
852 }