2 * summary of day panel
\r
4 * Copyright(c) 2008 olyutorskii
\r
5 * $Id: DaySummary.java 888 2009-11-04 06:23:35Z olyutorskii $
\r
8 package jp.sourceforge.jindolf;
\r
10 import java.awt.Color;
\r
11 import java.awt.Component;
\r
12 import java.awt.Container;
\r
13 import java.awt.Dimension;
\r
14 import java.awt.Frame;
\r
15 import java.awt.GridBagConstraints;
\r
16 import java.awt.GridBagLayout;
\r
17 import java.awt.Image;
\r
18 import java.awt.Insets;
\r
19 import java.awt.LayoutManager;
\r
20 import java.awt.event.ActionEvent;
\r
21 import java.awt.event.ActionListener;
\r
22 import java.awt.event.ItemEvent;
\r
23 import java.awt.event.ItemListener;
\r
24 import java.awt.event.WindowEvent;
\r
25 import java.awt.event.WindowListener;
\r
26 import java.text.NumberFormat;
\r
27 import java.util.HashMap;
\r
28 import java.util.List;
\r
29 import java.util.Map;
\r
30 import java.util.SortedSet;
\r
31 import java.util.TreeSet;
\r
32 import javax.swing.ImageIcon;
\r
33 import javax.swing.JButton;
\r
34 import javax.swing.JComboBox;
\r
35 import javax.swing.JDialog;
\r
36 import javax.swing.JLabel;
\r
37 import javax.swing.JScrollPane;
\r
38 import javax.swing.JSeparator;
\r
39 import javax.swing.JTable;
\r
40 import javax.swing.ListSelectionModel;
\r
41 import javax.swing.SwingConstants;
\r
42 import javax.swing.table.DefaultTableCellRenderer;
\r
43 import javax.swing.table.DefaultTableModel;
\r
44 import javax.swing.table.TableColumn;
\r
45 import javax.swing.table.TableColumnModel;
\r
46 import jp.sourceforge.jindolf.corelib.TalkType;
\r
51 @SuppressWarnings("serial")
\r
52 public class DaySummary extends JDialog
\r
53 implements WindowListener, ActionListener, ItemListener{
\r
54 private static final String FRAMETITLE =
\r
55 "発言集計 - " + Jindolf.TITLE;
\r
56 private static final NumberFormat AVERAGE_FORM;
\r
57 private static final String PUBTALK = "白発言";
\r
58 private static final String WOLFTALK = "赤発言";
\r
59 private static final String GRAVETALK = "青発言";
\r
60 private static final String PRVTALK = "灰発言";
\r
61 private static final String ALLTALK = "全発言";
\r
62 private static final int HORIZONTAL_GAP = 5;
\r
63 private static final int VERTICAL_GAP = 1;
\r
64 private static final Color COLOR_ALL = new Color(0xffff80);
\r
67 AVERAGE_FORM = NumberFormat.getInstance();
\r
68 AVERAGE_FORM.setMaximumFractionDigits(1);
\r
69 AVERAGE_FORM.setMinimumFractionDigits(1);
\r
76 private static DefaultTableModel createInitModel(){
\r
77 DefaultTableModel result;
\r
78 result = new DefaultTableModel();
\r
80 Object[] rowHeads = {"名前", "発言回数", "平均文字列長", "最終発言"};
\r
81 result.setColumnCount(rowHeads.length);
\r
82 result.setColumnIdentifiers(rowHeads);
\r
87 private final DefaultTableModel tableModel;
\r
88 private final TableColumn avatarColumn;
\r
90 private final JTable tableComp;
\r
91 private final JComboBox typeSelector = new JComboBox();
\r
92 private final JButton closeButton = new JButton("閉じる");
\r
93 private final JLabel caption = new JLabel();
\r
94 private final JLabel totalSum = new JLabel();
\r
96 private TalkType talkFilter;
\r
97 private Period period;
\r
101 * 集計結果を表示するモーダルダイアログを生成する。
\r
102 * @param owner オーナー
\r
104 public DaySummary(Frame owner){
\r
105 super(owner, FRAMETITLE, true);
\r
107 GUIUtils.modifyWindowAttributes(this, true, false, true);
\r
109 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
\r
110 addWindowListener(this);
\r
112 this.tableModel = createInitModel();
\r
113 this.tableComp = new JTable();
\r
114 this.tableComp.setModel(this.tableModel);
\r
115 this.tableComp.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
116 this.tableComp.setIntercellSpacing(
\r
117 new Dimension(HORIZONTAL_GAP, VERTICAL_GAP) );
\r
118 this.tableComp.setDefaultEditor(Object.class, null);
\r
119 this.tableComp.setDefaultRenderer(Object.class, new CustomRenderer());
\r
120 this.tableComp.setShowGrid(true);
\r
122 TableColumnModel tcolModel = this.tableComp.getColumnModel();
\r
124 this.avatarColumn = tcolModel.getColumn(0);
\r
126 DefaultTableCellRenderer renderer;
\r
128 renderer = new DefaultTableCellRenderer();
\r
129 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
\r
130 tcolModel.getColumn(1).setCellRenderer(renderer);
\r
132 renderer = new DefaultTableCellRenderer();
\r
133 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
\r
134 tcolModel.getColumn(2).setCellRenderer(renderer);
\r
136 renderer = new DefaultTableCellRenderer();
\r
137 renderer.setHorizontalAlignment(SwingConstants.RIGHT);
\r
138 tcolModel.getColumn(3).setCellRenderer(renderer);
\r
140 this.typeSelector.addItem(PUBTALK);
\r
141 this.typeSelector.addItem(WOLFTALK);
\r
142 this.typeSelector.addItem(GRAVETALK);
\r
143 this.typeSelector.addItem(PRVTALK);
\r
144 this.typeSelector.addItem(ALLTALK);
\r
146 this.closeButton.addActionListener(this);
\r
147 this.typeSelector.addItemListener(this);
\r
149 this.typeSelector.setSelectedItem(null);
\r
150 this.typeSelector.setSelectedItem(PUBTALK);
\r
162 private void clearModel(){
\r
163 int rows = this.tableModel.getRowCount();
\r
164 for(int ct = 1; ct <= rows; ct++){
\r
165 this.tableModel.removeRow(0);
\r
171 * @param avatar アバター
\r
172 * @param talkCount 発言回数
\r
173 * @param totalChars 発言文字総数
\r
174 * @param lastTime 最終発言時刻
\r
176 private void appendRow(Avatar avatar,
\r
178 Integer totalChars,
\r
180 String talks = talkCount + " 回";
\r
183 if(talkCount <= 0) average = 0.0;
\r
184 else average = (double)totalChars / (double)talkCount;
\r
185 String chars = AVERAGE_FORM.format(average) + " 文字";
\r
187 Object[] row = {avatar, talks, chars, lastTime};
\r
188 int rowIndex = this.tableModel.getRowCount();
\r
190 this.tableModel.insertRow(rowIndex, row);
\r
198 private void design(){
\r
199 Container content = getContentPane();
\r
201 LayoutManager layout = new GridBagLayout();
\r
202 GridBagConstraints constraints = new GridBagConstraints();
\r
203 content.setLayout(layout);
\r
205 constraints.insets = new Insets(5, 5, 5, 5);
\r
207 constraints.gridwidth = 1;
\r
208 constraints.fill = GridBagConstraints.NONE;
\r
209 constraints.anchor = GridBagConstraints.WEST;
\r
210 content.add(this.caption, constraints);
\r
212 constraints.gridwidth = GridBagConstraints.REMAINDER;
\r
213 constraints.fill = GridBagConstraints.NONE;
\r
214 content.add(this.typeSelector, constraints);
\r
216 JScrollPane scroller = new JScrollPane(this.tableComp);
\r
217 constraints.weightx = 1.0;
\r
218 constraints.weighty = 1.0;
\r
219 constraints.fill = GridBagConstraints.BOTH;
\r
220 content.add(scroller, constraints);
\r
222 constraints.weightx = 0.0;
\r
223 constraints.weighty = 0.0;
\r
224 constraints.fill = GridBagConstraints.NONE;
\r
225 constraints.anchor = GridBagConstraints.WEST;
\r
226 content.add(this.totalSum, constraints);
\r
228 constraints.weightx = 1.0;
\r
229 constraints.weighty = 0.0;
\r
230 constraints.fill = GridBagConstraints.HORIZONTAL;
\r
231 content.add(new JSeparator(), constraints);
\r
233 constraints.weightx = 0.0;
\r
234 constraints.weighty = 0.0;
\r
235 constraints.fill = GridBagConstraints.NONE;
\r
236 constraints.anchor = GridBagConstraints.EAST;
\r
237 content.add(this.closeButton, constraints);
\r
243 * 与えられたPeriodで集計を更新する。
\r
244 * @param newPeriod 日
\r
246 public void summaryPeriod(Period newPeriod){
\r
247 this.period = newPeriod;
\r
254 private void summaryPeriod(){
\r
257 if(this.period == null) return;
\r
259 SortedSet<Avatar> avatarSet = new TreeSet<Avatar>();
\r
260 Map<Avatar, Integer> talkCount = new HashMap<Avatar, Integer>();
\r
261 Map<Avatar, Integer> totalChars = new HashMap<Avatar, Integer>();
\r
262 Map<Avatar, Talk> lastTalk = new HashMap<Avatar, Talk>();
\r
264 List<Topic> topicList = this.period.getTopicList();
\r
265 for(Topic topic : topicList){
\r
266 if( ! (topic instanceof Talk)) continue;
\r
267 Talk talk = (Talk) topic;
\r
268 if(talk.getTalkCount() <= 0) continue;
\r
269 if( this.talkFilter != null
\r
270 && talk.getTalkType() != this.talkFilter) continue;
\r
272 Avatar avatar = talk.getAvatar();
\r
274 Integer counts = talkCount.get(avatar);
\r
275 if(counts == null) counts = Integer.valueOf(0);
\r
277 talkCount.put(avatar, counts);
\r
279 Integer total = totalChars.get(avatar);
\r
280 if(total == null) total = Integer.valueOf(0);
\r
281 total += talk.getTotalChars();
\r
282 totalChars.put(avatar, total);
\r
284 lastTalk.put(avatar, talk);
\r
286 avatarSet.add(avatar);
\r
290 for(Avatar avatar : avatarSet){
\r
291 Integer counts = talkCount.get(avatar);
\r
292 Integer total = totalChars.get(avatar);
\r
293 String lastTime = lastTalk.get(avatar).getAnchorNotation();
\r
294 appendRow(avatar, counts, total, lastTime);
\r
298 this.totalSum.setText("合計:" + sum + " 発言");
\r
300 Village village = this.period.getVillage();
\r
301 String villageName = village.getVillageName();
\r
302 String periodCaption = this.period.getCaption();
\r
303 this.caption.setText(villageName + "村 " + periodCaption);
\r
310 * @param event {@inheritDoc}
\r
312 public void windowActivated(WindowEvent event){
\r
318 * @param event {@inheritDoc}
\r
320 public void windowDeactivated(WindowEvent event){
\r
326 * @param event {@inheritDoc}
\r
328 public void windowIconified(WindowEvent event){
\r
334 * @param event {@inheritDoc}
\r
336 public void windowDeiconified(WindowEvent event){
\r
342 * @param event {@inheritDoc}
\r
344 public void windowOpened(WindowEvent event){
\r
350 * ダイアログのクローズボタン押下処理を行う。
\r
351 * @param event ウィンドウ変化イベント {@inheritDoc}
\r
353 public void windowClosing(WindowEvent event){
\r
360 * @param event {@inheritDoc}
\r
362 public void windowClosed(WindowEvent event){
\r
369 * @param event イベント {@inheritDoc}
\r
371 public void actionPerformed(ActionEvent event){
\r
372 if(event.getSource() != this.closeButton) return;
\r
380 * @param event イベント {@inheritDoc}
\r
382 public void itemStateChanged(ItemEvent event){
\r
383 if(event.getStateChange() != ItemEvent.SELECTED) return;
\r
385 Object selected = this.typeSelector.getSelectedItem();
\r
386 if (selected == PUBTALK) this.talkFilter = TalkType.PUBLIC;
\r
387 else if(selected == WOLFTALK) this.talkFilter = TalkType.WOLFONLY;
\r
388 else if(selected == GRAVETALK) this.talkFilter = TalkType.GRAVE;
\r
389 else if(selected == PRVTALK) this.talkFilter = TalkType.PRIVATE;
\r
390 else if(selected == ALLTALK) this.talkFilter = null;
\r
400 private void close(){
\r
402 this.period = null;
\r
408 * Avatar 顔イメージ描画用カスタムセルレンダラ。
\r
410 private class CustomRenderer extends DefaultTableCellRenderer{
\r
415 public CustomRenderer(){
\r
422 * セルに{@link Avatar}がきたら顔アイコンと名前を表示する。
\r
423 * @param value {@inheritDoc}
\r
426 public void setValue(Object value){
\r
427 if(value instanceof Avatar){
\r
428 Avatar avatar = (Avatar) value;
\r
430 Village village = DaySummary.this.period.getVillage();
\r
431 Image image = village.getAvatarFaceImage(avatar);
\r
432 if(image == null) image = village.getGraveImage();
\r
434 ImageIcon icon = new ImageIcon(image);
\r
438 setText(avatar.getName());
\r
440 Dimension prefSize = getPreferredSize();
\r
442 int cellHeight = VERTICAL_GAP * 2 + prefSize.height;
\r
443 if(DaySummary.this.tableComp.getRowHeight() < cellHeight){
\r
444 DaySummary.this.tableComp.setRowHeight(cellHeight);
\r
447 int cellWidth = HORIZONTAL_GAP * 2 + prefSize.width;
\r
448 if( DaySummary.this.avatarColumn.getPreferredWidth()
\r
450 DaySummary.this.avatarColumn.setPreferredWidth(cellWidth);
\r
456 super.setValue(value);
\r
464 * @param table {@inheritDoc}
\r
465 * @param value {@inheritDoc}
\r
466 * @param isSelected {@inheritDoc}
\r
467 * @param hasFocus {@inheritDoc}
\r
468 * @param row {@inheritDoc}
\r
469 * @param column {@inheritDoc}
\r
470 * @return {@inheritDoc}
\r
473 public Component getTableCellRendererComponent(JTable table,
\r
475 boolean isSelected,
\r
479 Component result = super.getTableCellRendererComponent(table,
\r
486 Object selected = DaySummary.this.typeSelector.getSelectedItem();
\r
487 Color bgColor = null;
\r
488 if(selected == PUBTALK){
\r
489 bgColor = TalkDraw.COLOR_PUBLIC;
\r
490 }else if(selected == WOLFTALK){
\r
491 bgColor = TalkDraw.COLOR_WOLFONLY;
\r
492 }else if(selected == GRAVETALK){
\r
493 bgColor = TalkDraw.COLOR_GRAVE;
\r
494 }else if(selected == PRVTALK){
\r
495 bgColor = TalkDraw.COLOR_PRIVATE;
\r
496 }else if(selected == ALLTALK){
\r
497 bgColor = COLOR_ALL;
\r
503 result.setForeground(Color.BLACK);
\r
504 result.setBackground(bgColor);
\r