4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sourceforge.jindolf;
10 import java.awt.Color;
11 import java.awt.Component;
12 import java.awt.Container;
13 import java.awt.Dimension;
14 import java.awt.Frame;
15 import java.awt.GridBagConstraints;
16 import java.awt.GridBagLayout;
17 import java.awt.Image;
18 import java.awt.Insets;
19 import java.awt.LayoutManager;
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.WindowEvent;
25 import java.awt.event.WindowListener;
26 import java.text.NumberFormat;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.SortedSet;
31 import java.util.TreeSet;
32 import javax.swing.ImageIcon;
33 import javax.swing.JButton;
34 import javax.swing.JComboBox;
35 import javax.swing.JDialog;
36 import javax.swing.JLabel;
37 import javax.swing.JScrollPane;
38 import javax.swing.JSeparator;
39 import javax.swing.JTable;
40 import javax.swing.ListSelectionModel;
41 import javax.swing.SwingConstants;
42 import javax.swing.table.DefaultTableCellRenderer;
43 import javax.swing.table.DefaultTableModel;
44 import javax.swing.table.TableColumn;
45 import javax.swing.table.TableColumnModel;
46 import jp.sourceforge.jindolf.corelib.TalkType;
51 @SuppressWarnings("serial")
52 public class DaySummary extends JDialog
53 implements WindowListener, ActionListener, ItemListener{
55 private static final String FRAMETITLE =
56 "発言集計 - " + Jindolf.TITLE;
57 private static final NumberFormat AVERAGE_FORM;
58 private static final String PUBTALK = "白発言";
59 private static final String WOLFTALK = "赤発言";
60 private static final String GRAVETALK = "青発言";
61 private static final String PRVTALK = "灰発言";
62 private static final String ALLTALK = "全発言";
63 private static final int HORIZONTAL_GAP = 5;
64 private static final int VERTICAL_GAP = 1;
65 private static final Color COLOR_ALL = new Color(0xffff80);
68 AVERAGE_FORM = NumberFormat.getInstance();
69 AVERAGE_FORM.setMaximumFractionDigits(1);
70 AVERAGE_FORM.setMinimumFractionDigits(1);
74 private final DefaultTableModel tableModel;
75 private final TableColumn avatarColumn;
77 private final JTable tableComp;
78 private final JComboBox typeSelector = new JComboBox();
79 private final JButton closeButton = new JButton("閉じる");
80 private final JLabel caption = new JLabel();
81 private final JLabel totalSum = new JLabel();
83 private TalkType talkFilter;
84 private Period period;
89 * 集計結果を表示するモーダルダイアログを生成する。
92 public DaySummary(Frame owner){
93 super(owner, FRAMETITLE, true);
95 GUIUtils.modifyWindowAttributes(this, true, false, true);
97 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
98 addWindowListener(this);
100 this.tableModel = createInitModel();
101 this.tableComp = new JTable();
102 this.tableComp.setModel(this.tableModel);
103 this.tableComp.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
104 this.tableComp.setIntercellSpacing(
105 new Dimension(HORIZONTAL_GAP, VERTICAL_GAP) );
106 this.tableComp.setDefaultEditor(Object.class, null);
107 this.tableComp.setDefaultRenderer(Object.class, new CustomRenderer());
108 this.tableComp.setShowGrid(true);
110 TableColumnModel tcolModel = this.tableComp.getColumnModel();
112 this.avatarColumn = tcolModel.getColumn(0);
114 DefaultTableCellRenderer renderer;
116 renderer = new DefaultTableCellRenderer();
117 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
118 tcolModel.getColumn(1).setCellRenderer(renderer);
120 renderer = new DefaultTableCellRenderer();
121 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
122 tcolModel.getColumn(2).setCellRenderer(renderer);
124 renderer = new DefaultTableCellRenderer();
125 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
126 tcolModel.getColumn(3).setCellRenderer(renderer);
128 this.typeSelector.addItem(PUBTALK);
129 this.typeSelector.addItem(WOLFTALK);
130 this.typeSelector.addItem(GRAVETALK);
131 this.typeSelector.addItem(PRVTALK);
132 this.typeSelector.addItem(ALLTALK);
134 this.closeButton.addActionListener(this);
135 this.typeSelector.addItemListener(this);
137 this.typeSelector.setSelectedItem(null);
138 this.typeSelector.setSelectedItem(PUBTALK);
152 private static DefaultTableModel createInitModel(){
153 DefaultTableModel result;
154 result = new DefaultTableModel();
156 Object[] rowHeads = {"名前", "発言回数", "平均文字列長", "最終発言"};
157 result.setColumnCount(rowHeads.length);
158 result.setColumnIdentifiers(rowHeads);
167 private void clearModel(){
168 int rows = this.tableModel.getRowCount();
169 for(int ct = 1; ct <= rows; ct++){
170 this.tableModel.removeRow(0);
177 * @param talkCount 発言回数
178 * @param totalChars 発言文字総数
179 * @param lastTime 最終発言時刻
181 private void appendRow(Avatar avatar,
185 String talks = talkCount + " 回";
188 if(talkCount <= 0) average = 0.0;
189 else average = (double)totalChars / (double)talkCount;
190 String chars = AVERAGE_FORM.format(average) + " 文字";
192 Object[] row = {avatar, talks, chars, lastTime};
193 int rowIndex = this.tableModel.getRowCount();
195 this.tableModel.insertRow(rowIndex, row);
203 private void design(){
204 Container content = getContentPane();
206 LayoutManager layout = new GridBagLayout();
207 GridBagConstraints constraints = new GridBagConstraints();
208 content.setLayout(layout);
210 constraints.insets = new Insets(5, 5, 5, 5);
212 constraints.gridwidth = 1;
213 constraints.fill = GridBagConstraints.NONE;
214 constraints.anchor = GridBagConstraints.WEST;
215 content.add(this.caption, constraints);
217 constraints.gridwidth = GridBagConstraints.REMAINDER;
218 constraints.fill = GridBagConstraints.NONE;
219 content.add(this.typeSelector, constraints);
221 JScrollPane scroller = new JScrollPane(this.tableComp);
222 constraints.weightx = 1.0;
223 constraints.weighty = 1.0;
224 constraints.fill = GridBagConstraints.BOTH;
225 content.add(scroller, constraints);
227 constraints.weightx = 0.0;
228 constraints.weighty = 0.0;
229 constraints.fill = GridBagConstraints.NONE;
230 constraints.anchor = GridBagConstraints.WEST;
231 content.add(this.totalSum, constraints);
233 constraints.weightx = 1.0;
234 constraints.weighty = 0.0;
235 constraints.fill = GridBagConstraints.HORIZONTAL;
236 content.add(new JSeparator(), constraints);
238 constraints.weightx = 0.0;
239 constraints.weighty = 0.0;
240 constraints.fill = GridBagConstraints.NONE;
241 constraints.anchor = GridBagConstraints.EAST;
242 content.add(this.closeButton, constraints);
248 * 与えられたPeriodで集計を更新する。
251 public void summaryPeriod(Period newPeriod){
252 this.period = newPeriod;
259 private void summaryPeriod(){
262 if(this.period == null) return;
264 SortedSet<Avatar> avatarSet = new TreeSet<Avatar>();
265 Map<Avatar, Integer> talkCount = new HashMap<Avatar, Integer>();
266 Map<Avatar, Integer> totalChars = new HashMap<Avatar, Integer>();
267 Map<Avatar, Talk> lastTalk = new HashMap<Avatar, Talk>();
269 List<Topic> topicList = this.period.getTopicList();
270 for(Topic topic : topicList){
271 if( ! (topic instanceof Talk)) continue;
272 Talk talk = (Talk) topic;
273 if(talk.getTalkCount() <= 0) continue;
274 if( this.talkFilter != null
275 && talk.getTalkType() != this.talkFilter) continue;
277 Avatar avatar = talk.getAvatar();
279 Integer counts = talkCount.get(avatar);
280 if(counts == null) counts = Integer.valueOf(0);
282 talkCount.put(avatar, counts);
284 Integer total = totalChars.get(avatar);
285 if(total == null) total = Integer.valueOf(0);
286 total += talk.getTotalChars();
287 totalChars.put(avatar, total);
289 lastTalk.put(avatar, talk);
291 avatarSet.add(avatar);
295 for(Avatar avatar : avatarSet){
296 Integer counts = talkCount.get(avatar);
297 Integer total = totalChars.get(avatar);
298 String lastTime = lastTalk.get(avatar).getAnchorNotation();
299 appendRow(avatar, counts, total, lastTime);
303 this.totalSum.setText("合計:" + sum + " 発言");
305 Village village = this.period.getVillage();
306 String villageName = village.getVillageName();
307 String periodCaption = this.period.getCaption();
308 this.caption.setText(villageName + "村 " + periodCaption);
315 * @param event {@inheritDoc}
318 public void windowActivated(WindowEvent event){
324 * @param event {@inheritDoc}
327 public void windowDeactivated(WindowEvent event){
333 * @param event {@inheritDoc}
336 public void windowIconified(WindowEvent event){
342 * @param event {@inheritDoc}
345 public void windowDeiconified(WindowEvent event){
351 * @param event {@inheritDoc}
354 public void windowOpened(WindowEvent event){
360 * ダイアログのクローズボタン押下処理を行う。
361 * @param event ウィンドウ変化イベント {@inheritDoc}
364 public void windowClosing(WindowEvent event){
371 * @param event {@inheritDoc}
374 public void windowClosed(WindowEvent event){
381 * @param event イベント {@inheritDoc}
384 public void actionPerformed(ActionEvent event){
385 if(event.getSource() != this.closeButton) return;
393 * @param event イベント {@inheritDoc}
396 public void itemStateChanged(ItemEvent event){
397 if(event.getStateChange() != ItemEvent.SELECTED) return;
399 Object selected = this.typeSelector.getSelectedItem();
400 if (selected == PUBTALK) this.talkFilter = TalkType.PUBLIC;
401 else if(selected == WOLFTALK) this.talkFilter = TalkType.WOLFONLY;
402 else if(selected == GRAVETALK) this.talkFilter = TalkType.GRAVE;
403 else if(selected == PRVTALK) this.talkFilter = TalkType.PRIVATE;
404 else if(selected == ALLTALK) this.talkFilter = null;
414 private void close(){
422 * Avatar 顔イメージ描画用カスタムセルレンダラ。
424 private class CustomRenderer extends DefaultTableCellRenderer{
429 public CustomRenderer(){
436 * セルに{@link Avatar}がきたら顔アイコンと名前を表示する。
437 * @param value {@inheritDoc}
440 public void setValue(Object value){
441 if(value instanceof Avatar){
442 Avatar avatar = (Avatar) value;
444 Village village = DaySummary.this.period.getVillage();
445 Image image = village.getAvatarFaceImage(avatar);
446 if(image == null) image = village.getGraveImage();
448 ImageIcon icon = new ImageIcon(image);
452 setText(avatar.getName());
454 Dimension prefSize = getPreferredSize();
456 int cellHeight = VERTICAL_GAP * 2 + prefSize.height;
457 if(DaySummary.this.tableComp.getRowHeight() < cellHeight){
458 DaySummary.this.tableComp.setRowHeight(cellHeight);
461 int cellWidth = HORIZONTAL_GAP * 2 + prefSize.width;
462 if( DaySummary.this.avatarColumn.getPreferredWidth()
464 DaySummary.this.avatarColumn.setPreferredWidth(cellWidth);
470 super.setValue(value);
478 * @param table {@inheritDoc}
479 * @param value {@inheritDoc}
480 * @param isSelected {@inheritDoc}
481 * @param hasFocus {@inheritDoc}
482 * @param row {@inheritDoc}
483 * @param column {@inheritDoc}
484 * @return {@inheritDoc}
487 public Component getTableCellRendererComponent(JTable table,
493 Component result = super.getTableCellRendererComponent(table,
500 Object selected = DaySummary.this.typeSelector.getSelectedItem();
501 Color bgColor = null;
502 if(selected == PUBTALK){
503 bgColor = TalkDraw.COLOR_PUBLIC;
504 }else if(selected == WOLFTALK){
505 bgColor = TalkDraw.COLOR_WOLFONLY;
506 }else if(selected == GRAVETALK){
507 bgColor = TalkDraw.COLOR_GRAVE;
508 }else if(selected == PRVTALK){
509 bgColor = TalkDraw.COLOR_PRIVATE;
510 }else if(selected == ALLTALK){
517 result.setForeground(Color.BLACK);
518 result.setBackground(bgColor);