4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sourceforge.jindolf;
10 import java.awt.Container;
11 import java.awt.Frame;
12 import java.awt.GridBagConstraints;
13 import java.awt.GridBagLayout;
14 import java.awt.Insets;
15 import java.awt.event.ActionEvent;
16 import java.awt.event.ActionListener;
17 import java.util.BitSet;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.List;
22 import javax.swing.BorderFactory;
23 import javax.swing.JButton;
24 import javax.swing.JCheckBox;
25 import javax.swing.JComponent;
26 import javax.swing.JDialog;
27 import javax.swing.JPanel;
28 import javax.swing.JSeparator;
29 import javax.swing.SwingConstants;
30 import javax.swing.border.Border;
31 import javax.swing.event.ChangeEvent;
32 import javax.swing.event.ChangeListener;
33 import javax.swing.event.EventListenerList;
34 import jp.sourceforge.jindolf.corelib.EventFamily;
35 import jp.sourceforge.jindolf.corelib.TalkType;
40 @SuppressWarnings("serial")
41 public class FilterPanel extends JDialog
42 implements ActionListener, TopicFilter{
44 private static final int COLS = 4;
46 private static final String FRAMETITLE = "発言フィルタ - " + Jindolf.TITLE;
48 private final JCheckBox checkPublic = new JCheckBox("公開", true);
49 private final JCheckBox checkWolf = new JCheckBox("狼", true);
50 private final JCheckBox checkPrivate = new JCheckBox("独り言", true);
51 private final JCheckBox checkGrave = new JCheckBox("墓下", true);
52 private final JCheckBox checkExtra = new JCheckBox("Extra", true);
54 private final JButton selAllButton = new JButton("全選択");
55 private final JButton selNoneButton = new JButton("全解除");
56 private final JButton negateButton = new JButton("反転");
58 private final JCheckBox checkRealtime =
59 new JCheckBox("リアルタイム更新", true);
60 private final JButton applyButton = new JButton("フィルタ適用");
62 private final Map<Avatar, JCheckBox> cbMap =
63 new HashMap<Avatar, JCheckBox>();
64 private final List<JCheckBox> cbList = new LinkedList<JCheckBox>();
66 private final EventListenerList listeners = new EventListenerList();
70 * @param owner フレームオーナー
72 public FilterPanel(Frame owner){
73 super(owner, FRAMETITLE, false);
75 GUIUtils.modifyWindowAttributes(this, true, false, true);
77 JComponent topicPanel = createTopicPanel();
78 JComponent avatarPanel = createAvatarPanel();
79 JComponent buttonPanel = createButtonPanel();
80 JComponent bottomPanel = createBottomPanel();
81 design(topicPanel, avatarPanel, buttonPanel, bottomPanel);
83 this.checkPublic.addActionListener(this);
84 this.checkWolf.addActionListener(this);
85 this.checkPrivate.addActionListener(this);
86 this.checkGrave.addActionListener(this);
87 this.checkExtra.addActionListener(this);
89 for(JCheckBox avatarCheckBox : this.cbList){
90 avatarCheckBox.addActionListener(this);
93 this.selAllButton.addActionListener(this);
94 this.selNoneButton.addActionListener(this);
95 this.negateButton.addActionListener(this);
97 this.checkRealtime.addActionListener(this);
98 this.applyButton.addActionListener(this);
99 this.applyButton.setEnabled(false);
106 * @param topicPanel システムイベント選択
107 * @param avatarPanel キャラ一覧
108 * @param buttonPanel ボタン群
109 * @param bottomPanel 下段パネル
111 private void design(JComponent topicPanel,
112 JComponent avatarPanel,
113 JComponent buttonPanel,
114 JComponent bottomPanel ){
115 Container content = getContentPane();
117 GridBagLayout layout = new GridBagLayout();
118 GridBagConstraints constraints = new GridBagConstraints();
120 content.setLayout(layout);
122 constraints.weightx = 1.0 / 5;
123 constraints.weighty = 1.0;
124 constraints.gridheight = 3;
125 constraints.fill = GridBagConstraints.BOTH;
126 constraints.anchor = GridBagConstraints.CENTER;
127 content.add(topicPanel, constraints);
129 constraints.weightx = 0.0;
130 constraints.fill = GridBagConstraints.VERTICAL;
131 constraints.insets = new Insets(3, 0, 3, 0);
132 content.add(new JSeparator(SwingConstants.VERTICAL), constraints);
134 constraints.weightx = 4.0 / 5;
135 constraints.weighty = 0.0;
136 constraints.gridheight = 1;
137 constraints.gridwidth = GridBagConstraints.REMAINDER;
138 constraints.fill = GridBagConstraints.HORIZONTAL;
139 constraints.insets = new Insets(0, 0, 0, 0);
140 content.add(buttonPanel, constraints);
142 constraints.insets = new Insets(0, 3, 0, 3);
143 content.add(new JSeparator(), constraints);
145 constraints.weighty = 1.0;
146 constraints.fill = GridBagConstraints.BOTH;
147 constraints.insets = new Insets(0, 0, 0, 0);
148 content.add(avatarPanel, constraints);
150 constraints.weightx = 1.0;
151 constraints.gridwidth = GridBagConstraints.REMAINDER;
152 constraints.fill = GridBagConstraints.HORIZONTAL;
153 content.add(new JSeparator(SwingConstants.HORIZONTAL), constraints);
155 constraints.fill = GridBagConstraints.NONE;
156 constraints.anchor = GridBagConstraints.NORTHEAST;
157 content.add(bottomPanel, constraints);
163 * システムイベントチェックボックス群パネルを作成。
164 * @return システムイベントチェックボックス群パネル
166 private JComponent createTopicPanel(){
167 this.checkPublic.setToolTipText("誰にでも見える発言");
168 this.checkWolf.setToolTipText("人狼同士にしか見えない発言");
169 this.checkPrivate.setToolTipText("本人にしか見えない発言");
170 this.checkGrave.setToolTipText("死者同士にしか見えない発言");
171 this.checkExtra.setToolTipText("占い先や護衛先などのシステムメッセージ");
173 JPanel topicPanel = new JPanel();
175 Border border = BorderFactory.createEmptyBorder(2, 2, 2, 2);
176 topicPanel.setBorder(border);
178 GridBagLayout layout = new GridBagLayout();
179 GridBagConstraints constraints = new GridBagConstraints();
181 topicPanel.setLayout(layout);
183 constraints.anchor = GridBagConstraints.WEST;
184 constraints.weightx = 1.0;
185 constraints.weighty = 1.0;
187 constraints.gridwidth = GridBagConstraints.REMAINDER;
188 topicPanel.add(this.checkPublic, constraints);
190 constraints.gridwidth = GridBagConstraints.REMAINDER;
191 topicPanel.add(this.checkWolf, constraints);
193 constraints.gridwidth = GridBagConstraints.REMAINDER;
194 topicPanel.add(this.checkPrivate, constraints);
196 constraints.gridwidth = GridBagConstraints.REMAINDER;
197 topicPanel.add(this.checkGrave, constraints);
199 constraints.gridwidth = GridBagConstraints.REMAINDER;
200 topicPanel.add(this.checkExtra, constraints);
206 * キャラ一覧チェックボックス群パネルを作成。
207 * @return キャラ一覧チェックボックス群パネル
209 private JComponent createAvatarPanel(){
210 JPanel avatarPanel = new JPanel();
212 Border border = BorderFactory.createEmptyBorder(2, 2, 2, 2);
213 avatarPanel.setBorder(border);
215 GridBagLayout layout = new GridBagLayout();
216 GridBagConstraints constraints = new GridBagConstraints();
218 avatarPanel.setLayout(layout);
220 constraints.weightx = 1.0 / COLS;
221 constraints.weighty = 1.0;
222 constraints.anchor = GridBagConstraints.WEST;
225 for(Avatar avatar : Avatar.getPredefinedAvatarList()){
226 JCheckBox checkBox = new JCheckBox(avatar.getName(), true);
227 checkBox.setToolTipText(avatar.getJobTitle());
228 this.cbList.add(checkBox);
229 if(xPos >= COLS - 1){
230 constraints.gridwidth = GridBagConstraints.REMAINDER;
233 constraints.gridwidth = 1;
236 avatarPanel.add(checkBox, constraints);
237 this.cbMap.put(avatar, checkBox);
247 private JComponent createButtonPanel(){
248 this.selAllButton.setToolTipText(
250 this.selNoneButton.setToolTipText(
251 "全キャラクタの発言をフィルタリングする");
252 this.negateButton.setToolTipText(
253 "(表示⇔フィルタリング)の設定を反転させる");
255 JPanel buttonPanel = new JPanel();
257 GridBagLayout layout = new GridBagLayout();
258 GridBagConstraints constraints = new GridBagConstraints();
260 buttonPanel.setLayout(layout);
262 constraints.weightx = 1.0 / 3;
263 constraints.insets = new Insets(3, 3, 3, 3);
264 buttonPanel.add(this.selAllButton, constraints);
265 buttonPanel.add(this.selNoneButton, constraints);
266 buttonPanel.add(this.negateButton, constraints);
275 private JComponent createBottomPanel(){
276 JPanel panel = new JPanel();
278 GridBagLayout layout = new GridBagLayout();
279 GridBagConstraints constraints = new GridBagConstraints();
281 panel.setLayout(layout);
283 constraints.fill = GridBagConstraints.NONE;
284 constraints.insets = new Insets(3, 3, 3, 3);
285 panel.add(this.checkRealtime, constraints);
286 panel.add(this.applyButton, constraints);
293 * @param listener リスナ
295 public void addChangeListener(ChangeListener listener){
296 this.listeners.add(ChangeListener.class, listener);
301 * @param listener リスナ
303 public void removeChangeListener(ChangeListener listener){
304 this.listeners.remove(ChangeListener.class, listener);
311 public ChangeListener[] getChangeListeners(){
312 return this.listeners.getListeners(ChangeListener.class);
318 protected void fireCheckChanged(){
319 ChangeEvent changeEvent = new ChangeEvent(this);
320 for(ChangeListener listener : getChangeListeners()){
321 listener.stateChanged(changeEvent);
328 public void initButtons(){
329 this.checkPublic.setSelected(true);
330 this.checkWolf.setSelected(true);
331 this.checkPrivate.setSelected(true);
332 this.checkGrave.setSelected(true);
333 this.checkExtra.setSelected(true);
335 this.selAllButton.doClick();
341 * チェックボックスまたはボタン操作時にリスナとして呼ばれる。
346 public void actionPerformed(ActionEvent event){
347 Object source = event.getSource();
349 boolean isRealtime = this.checkRealtime.isSelected();
351 if(source == this.selAllButton){
352 boolean hasChanged = false;
353 for(JCheckBox avatarCBox : this.cbList){
354 if( ! avatarCBox.isSelected()){
355 avatarCBox.setSelected(true);
359 if(isRealtime && hasChanged){
362 }else if(source == this.selNoneButton){
363 boolean hasChanged = false;
364 for(JCheckBox avatarCBox : this.cbList){
365 if(avatarCBox.isSelected()){
366 avatarCBox.setSelected(false);
370 if(isRealtime && hasChanged){
373 }else if(source == this.negateButton){
374 for(JCheckBox avatarCBox : this.cbList){
375 if(avatarCBox.isSelected()){
376 avatarCBox.setSelected(false);
378 avatarCBox.setSelected(true);
384 }else if(source == this.checkRealtime){
386 this.applyButton.setEnabled(false);
389 this.applyButton.setEnabled(true);
391 }else if(source == this.applyButton){
393 }else if(source instanceof JCheckBox){
404 * @param topic {@inheritDoc}
405 * @return {@inheritDoc}
408 public boolean isFiltered(Topic topic){
410 if(topic instanceof Talk){
412 }else if(topic instanceof SysEvent){
413 SysEvent sysEvent = (SysEvent) topic;
414 if(sysEvent.getEventFamily() == EventFamily.EXTRA){
415 if( ! this.checkExtra.isSelected() ){
426 TalkType type = talk.getTalkType();
429 cbox = this.checkPublic;
432 cbox = this.checkWolf;
435 cbox = this.checkPrivate;
438 cbox = this.checkGrave;
444 if( ! cbox.isSelected()){
448 Avatar avatar = talk.getAvatar();
449 cbox = this.cbMap.get(avatar);
450 if( cbox != null && ! cbox.isSelected()){
459 * @return {@inheritDoc}
462 public FilterContext getFilterContext(){
463 return new FilterPanelContext();
468 * @param context {@inheritDoc}
469 * @return {@inheritDoc}
472 public boolean isSame(FilterContext context){
473 if(context == null) return false;
474 if( ! (context instanceof FilterPanelContext) ) return false;
475 FilterPanelContext argContext = (FilterPanelContext) context;
476 FilterPanelContext thisContext =
477 (FilterPanelContext) getFilterContext();
479 return thisContext.context.equals(argContext.context);
485 private final class FilterPanelContext implements FilterContext{
487 private final BitSet context = new BitSet();
492 public FilterPanelContext(){
496 this.context.set(index++,
497 FilterPanel.this.checkPublic.isSelected());
498 this.context.set(index++,
499 FilterPanel.this.checkWolf.isSelected());
500 this.context.set(index++,
501 FilterPanel.this.checkPrivate.isSelected());
502 this.context.set(index++,
503 FilterPanel.this.checkGrave.isSelected());
504 this.context.set(index++,
505 FilterPanel.this.checkExtra.isSelected());
507 for(Avatar avatar : Avatar.getPredefinedAvatarList()){
508 JCheckBox checkBox = FilterPanel.this.cbMap.get(avatar);
509 this.context.set(index++, checkBox.isSelected());
517 * @return {@inheritDoc}
520 public String toString(){
521 return this.context.toString();