-/*\r
- * Filter panel\r
- *\r
- * Copyright(c) 2008 olyutorskii\r
- * $Id: FilterPanel.java 969 2009-12-24 16:12:58Z olyutorskii $\r
- */\r
-\r
-package jp.sourceforge.jindolf;\r
-\r
-import java.awt.Container;\r
-import java.awt.Frame;\r
-import java.awt.GridBagConstraints;\r
-import java.awt.GridBagLayout;\r
-import java.awt.Insets;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ActionListener;\r
-import java.util.BitSet;\r
-import java.util.HashMap;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Map;\r
-import javax.swing.BorderFactory;\r
-import javax.swing.JButton;\r
-import javax.swing.JCheckBox;\r
-import javax.swing.JComponent;\r
-import javax.swing.JDialog;\r
-import javax.swing.JPanel;\r
-import javax.swing.JSeparator;\r
-import javax.swing.SwingConstants;\r
-import javax.swing.border.Border;\r
-import javax.swing.event.ChangeEvent;\r
-import javax.swing.event.ChangeListener;\r
-import javax.swing.event.EventListenerList;\r
-import jp.sourceforge.jindolf.corelib.EventFamily;\r
-import jp.sourceforge.jindolf.corelib.TalkType;\r
-\r
-/**\r
- * 発言フィルタ GUI。\r
- */\r
-@SuppressWarnings("serial")\r
-public class FilterPanel extends JDialog\r
- implements ActionListener, TopicFilter{\r
-\r
- private static final int COLS = 4;\r
-\r
- private static final String FRAMETITLE = "発言フィルタ - " + Jindolf.TITLE;\r
-\r
- private final JCheckBox checkPublic = new JCheckBox("公開", true);\r
- private final JCheckBox checkWolf = new JCheckBox("狼", true);\r
- private final JCheckBox checkPrivate = new JCheckBox("独り言", true);\r
- private final JCheckBox checkGrave = new JCheckBox("墓下", true);\r
- private final JCheckBox checkExtra = new JCheckBox("Extra", true);\r
-\r
- private final JButton selAllButton = new JButton("全選択");\r
- private final JButton selNoneButton = new JButton("全解除");\r
- private final JButton negateButton = new JButton("反転");\r
-\r
- private final JCheckBox checkRealtime =\r
- new JCheckBox("リアルタイム更新", true);\r
- private final JButton applyButton = new JButton("フィルタ適用");\r
-\r
- private final Map<Avatar, JCheckBox> cbMap =\r
- new HashMap<Avatar, JCheckBox>();\r
- private final List<JCheckBox> cbList = new LinkedList<JCheckBox>();\r
-\r
- private final EventListenerList listeners = new EventListenerList();\r
-\r
- /**\r
- * 発言フィルタを生成する。\r
- * @param owner フレームオーナー\r
- */\r
- public FilterPanel(Frame owner){\r
- super(owner, FRAMETITLE, false);\r
-\r
- GUIUtils.modifyWindowAttributes(this, true, false, true);\r
-\r
- JComponent topicPanel = createTopicPanel();\r
- JComponent avatarPanel = createAvatarPanel();\r
- JComponent buttonPanel = createButtonPanel();\r
- JComponent bottomPanel = createBottomPanel();\r
- design(topicPanel, avatarPanel, buttonPanel, bottomPanel);\r
-\r
- this.checkPublic.addActionListener(this);\r
- this.checkWolf.addActionListener(this);\r
- this.checkPrivate.addActionListener(this);\r
- this.checkGrave.addActionListener(this);\r
- this.checkExtra.addActionListener(this);\r
-\r
- for(JCheckBox avatarCheckBox : this.cbList){\r
- avatarCheckBox.addActionListener(this);\r
- }\r
-\r
- this.selAllButton.addActionListener(this);\r
- this.selNoneButton.addActionListener(this);\r
- this.negateButton.addActionListener(this);\r
-\r
- this.checkRealtime.addActionListener(this);\r
- this.applyButton.addActionListener(this);\r
- this.applyButton.setEnabled(false);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * レイアウトデザインを行う。\r
- * @param topicPanel システムイベント選択\r
- * @param avatarPanel キャラ一覧\r
- * @param buttonPanel ボタン群\r
- * @param bottomPanel 下段パネル\r
- */\r
- private void design(JComponent topicPanel,\r
- JComponent avatarPanel,\r
- JComponent buttonPanel,\r
- JComponent bottomPanel ){\r
- Container content = getContentPane();\r
-\r
- GridBagLayout layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- content.setLayout(layout);\r
-\r
- constraints.weightx = 1.0 / 5;\r
- constraints.weighty = 1.0;\r
- constraints.gridheight = 3;\r
- constraints.fill = GridBagConstraints.BOTH;\r
- constraints.anchor = GridBagConstraints.CENTER;\r
- content.add(topicPanel, constraints);\r
-\r
- constraints.weightx = 0.0;\r
- constraints.fill = GridBagConstraints.VERTICAL;\r
- constraints.insets = new Insets(3, 0, 3, 0);\r
- content.add(new JSeparator(SwingConstants.VERTICAL), constraints);\r
-\r
- constraints.weightx = 4.0 / 5;\r
- constraints.weighty = 0.0;\r
- constraints.gridheight = 1;\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- constraints.fill = GridBagConstraints.HORIZONTAL;\r
- constraints.insets = new Insets(0, 0, 0, 0);\r
- content.add(buttonPanel, constraints);\r
-\r
- constraints.insets = new Insets(0, 3, 0, 3);\r
- content.add(new JSeparator(), constraints);\r
-\r
- constraints.weighty = 1.0;\r
- constraints.fill = GridBagConstraints.BOTH;\r
- constraints.insets = new Insets(0, 0, 0, 0);\r
- content.add(avatarPanel, constraints);\r
-\r
- constraints.weightx = 1.0;\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- constraints.fill = GridBagConstraints.HORIZONTAL;\r
- content.add(new JSeparator(SwingConstants.HORIZONTAL), constraints);\r
-\r
- constraints.fill = GridBagConstraints.NONE;\r
- constraints.anchor = GridBagConstraints.NORTHEAST;\r
- content.add(bottomPanel, constraints);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * システムイベントチェックボックス群パネルを作成。\r
- * @return システムイベントチェックボックス群パネル\r
- */\r
- private JComponent createTopicPanel(){\r
- this.checkPublic.setToolTipText("誰にでも見える発言");\r
- this.checkWolf.setToolTipText("人狼同士にしか見えない発言");\r
- this.checkPrivate.setToolTipText("本人にしか見えない発言");\r
- this.checkGrave.setToolTipText("死者同士にしか見えない発言");\r
- this.checkExtra.setToolTipText("占い先や護衛先などのシステムメッセージ");\r
-\r
- JPanel topicPanel = new JPanel();\r
-\r
- Border border = BorderFactory.createEmptyBorder(2, 2, 2, 2);\r
- topicPanel.setBorder(border);\r
-\r
- GridBagLayout layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- topicPanel.setLayout(layout);\r
-\r
- constraints.anchor = GridBagConstraints.WEST;\r
- constraints.weightx = 1.0;\r
- constraints.weighty = 1.0;\r
-\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- topicPanel.add(this.checkPublic, constraints);\r
-\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- topicPanel.add(this.checkWolf, constraints);\r
-\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- topicPanel.add(this.checkPrivate, constraints);\r
-\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- topicPanel.add(this.checkGrave, constraints);\r
-\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- topicPanel.add(this.checkExtra, constraints);\r
-\r
- return topicPanel;\r
- }\r
-\r
- /**\r
- * キャラ一覧チェックボックス群パネルを作成。\r
- * @return キャラ一覧チェックボックス群パネル\r
- */\r
- private JComponent createAvatarPanel(){\r
- JPanel avatarPanel = new JPanel();\r
-\r
- Border border = BorderFactory.createEmptyBorder(2, 2, 2, 2);\r
- avatarPanel.setBorder(border);\r
-\r
- GridBagLayout layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- avatarPanel.setLayout(layout);\r
-\r
- constraints.weightx = 1.0 / COLS;\r
- constraints.weighty = 1.0;\r
- constraints.anchor = GridBagConstraints.WEST;\r
-\r
- int xPos = 0;\r
- for(Avatar avatar : Avatar.getPredefinedAvatarList()){\r
- JCheckBox checkBox = new JCheckBox(avatar.getName(), true);\r
- checkBox.setToolTipText(avatar.getJobTitle());\r
- this.cbList.add(checkBox);\r
- if(xPos >= COLS - 1){\r
- constraints.gridwidth = GridBagConstraints.REMAINDER;\r
- xPos = 0;\r
- }else{\r
- constraints.gridwidth = 1;\r
- xPos++;\r
- }\r
- avatarPanel.add(checkBox, constraints);\r
- this.cbMap.put(avatar, checkBox);\r
- }\r
-\r
- return avatarPanel;\r
- }\r
-\r
- /**\r
- * ボタン群パネルを生成。\r
- * @return ボタン群パネル\r
- */\r
- private JComponent createButtonPanel(){\r
- this.selAllButton.setToolTipText(\r
- "全キャラクタの発言を表示する");\r
- this.selNoneButton.setToolTipText(\r
- "全キャラクタの発言をフィルタリングする");\r
- this.negateButton.setToolTipText(\r
- "(表示⇔フィルタリング)の設定を反転させる");\r
-\r
- JPanel buttonPanel = new JPanel();\r
-\r
- GridBagLayout layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- buttonPanel.setLayout(layout);\r
-\r
- constraints.weightx = 1.0 / 3;\r
- constraints.insets = new Insets(3, 3, 3, 3);\r
- buttonPanel.add(this.selAllButton, constraints);\r
- buttonPanel.add(this.selNoneButton, constraints);\r
- buttonPanel.add(this.negateButton, constraints);\r
-\r
- return buttonPanel;\r
- }\r
-\r
- /**\r
- * 下段パネルを生成する。\r
- * @return 下段パネル\r
- */\r
- private JComponent createBottomPanel(){\r
- JPanel panel = new JPanel();\r
-\r
- GridBagLayout layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- panel.setLayout(layout);\r
-\r
- constraints.fill = GridBagConstraints.NONE;\r
- constraints.insets = new Insets(3, 3, 3, 3);\r
- panel.add(this.checkRealtime, constraints);\r
- panel.add(this.applyButton, constraints);\r
-\r
- return panel;\r
- }\r
-\r
- /**\r
- * リスナを登録する。\r
- * @param listener リスナ\r
- */\r
- public void addChangeListener(ChangeListener listener){\r
- this.listeners.add(ChangeListener.class, listener);\r
- }\r
-\r
- /**\r
- * リスナを削除する。\r
- * @param listener リスナ\r
- */\r
- public void removeChangeListener(ChangeListener listener){\r
- this.listeners.remove(ChangeListener.class, listener);\r
- }\r
-\r
- /**\r
- * 全リスナを取得する。\r
- * @return リスナの配列\r
- */\r
- public ChangeListener[] getChangeListeners(){\r
- return this.listeners.getListeners(ChangeListener.class);\r
- }\r
-\r
- /**\r
- * 全リスナへフィルタ操作を通知する。\r
- */\r
- protected void fireCheckChanged(){\r
- ChangeEvent changeEvent = new ChangeEvent(this);\r
- for(ChangeListener listener : getChangeListeners()){\r
- listener.stateChanged(changeEvent);\r
- }\r
- }\r
-\r
- /**\r
- * ボタン状態の初期化。\r
- */\r
- public void initButtons(){\r
- this.checkPublic.setSelected(true);\r
- this.checkWolf.setSelected(true);\r
- this.checkPrivate.setSelected(true);\r
- this.checkGrave.setSelected(true);\r
- this.checkExtra.setSelected(true);\r
-\r
- this.selAllButton.doClick();\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * チェックボックスまたはボタン操作時にリスナとして呼ばれる。\r
- * {@inheritDoc}\r
- * @param event イベント\r
- */\r
- public void actionPerformed(ActionEvent event){\r
- Object source = event.getSource();\r
-\r
- boolean isRealtime = this.checkRealtime.isSelected();\r
-\r
- if(source == this.selAllButton){\r
- boolean hasChanged = false;\r
- for(JCheckBox avatarCBox : this.cbList){\r
- if( ! avatarCBox.isSelected()){\r
- avatarCBox.setSelected(true);\r
- hasChanged = true;\r
- }\r
- }\r
- if(isRealtime && hasChanged){\r
- fireCheckChanged();\r
- }\r
- }else if(source == this.selNoneButton){\r
- boolean hasChanged = false;\r
- for(JCheckBox avatarCBox : this.cbList){\r
- if(avatarCBox.isSelected()){\r
- avatarCBox.setSelected(false);\r
- hasChanged = true;\r
- }\r
- }\r
- if(isRealtime && hasChanged){\r
- fireCheckChanged();\r
- }\r
- }else if(source == this.negateButton){\r
- for(JCheckBox avatarCBox : this.cbList){\r
- if(avatarCBox.isSelected()){\r
- avatarCBox.setSelected(false);\r
- }else{\r
- avatarCBox.setSelected(true);\r
- }\r
- }\r
- if(isRealtime){\r
- fireCheckChanged();\r
- }\r
- }else if(source == this.checkRealtime){\r
- if(isRealtime){\r
- this.applyButton.setEnabled(false);\r
- fireCheckChanged();\r
- }else{\r
- this.applyButton.setEnabled(true);\r
- }\r
- }else if(source == this.applyButton){\r
- fireCheckChanged();\r
- }else if(source instanceof JCheckBox){\r
- if(isRealtime){\r
- fireCheckChanged();\r
- }\r
- }\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- * @param topic {@inheritDoc}\r
- * @return {@inheritDoc}\r
- */\r
- public boolean isFiltered(Topic topic){\r
- Talk talk;\r
- if(topic instanceof Talk){\r
- talk = (Talk) topic;\r
- }else if(topic instanceof SysEvent){\r
- SysEvent sysEvent = (SysEvent) topic;\r
- if(sysEvent.getEventFamily() == EventFamily.EXTRA){\r
- if( ! this.checkExtra.isSelected() ){\r
- return true;\r
- }\r
- }\r
- return false;\r
- }else{\r
- return false;\r
- }\r
-\r
- JCheckBox cbox;\r
-\r
- TalkType type = talk.getTalkType();\r
- switch(type){\r
- case PUBLIC:\r
- cbox = this.checkPublic;\r
- break;\r
- case WOLFONLY:\r
- cbox = this.checkWolf;\r
- break;\r
- case PRIVATE:\r
- cbox = this.checkPrivate;\r
- break;\r
- case GRAVE:\r
- cbox = this.checkGrave;\r
- break;\r
- default:\r
- assert false;\r
- return true;\r
- }\r
- if( ! cbox.isSelected()){\r
- return true;\r
- }\r
-\r
- Avatar avatar = talk.getAvatar();\r
- cbox = this.cbMap.get(avatar);\r
- if( cbox != null && ! cbox.isSelected()){\r
- return true;\r
- }\r
-\r
- return false;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- * @return {@inheritDoc}\r
- */\r
- public FilterContext getFilterContext(){\r
- return new FilterPanelContext();\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- * @param context {@inheritDoc}\r
- * @return {@inheritDoc}\r
- */\r
- public boolean isSame(FilterContext context){\r
- if(context == null) return false;\r
- if( ! (context instanceof FilterPanelContext) ) return false;\r
- FilterPanelContext argContext = (FilterPanelContext) context;\r
- FilterPanelContext thisContext =\r
- (FilterPanelContext) getFilterContext();\r
-\r
- return thisContext.context.equals(argContext.context);\r
- }\r
-\r
- /**\r
- * カスタム化されたフィルタ状態。\r
- */\r
- private final class FilterPanelContext implements FilterContext{\r
-\r
- private final BitSet context = new BitSet();\r
-\r
- /**\r
- * コンストラクタ。\r
- */\r
- public FilterPanelContext(){\r
- super();\r
-\r
- int index = 0;\r
- this.context.set(index++,\r
- FilterPanel.this.checkPublic.isSelected());\r
- this.context.set(index++,\r
- FilterPanel.this.checkWolf.isSelected());\r
- this.context.set(index++,\r
- FilterPanel.this.checkPrivate.isSelected());\r
- this.context.set(index++,\r
- FilterPanel.this.checkGrave.isSelected());\r
- this.context.set(index++,\r
- FilterPanel.this.checkExtra.isSelected());\r
-\r
- for(Avatar avatar : Avatar.getPredefinedAvatarList()){\r
- JCheckBox checkBox = FilterPanel.this.cbMap.get(avatar);\r
- this.context.set(index++, checkBox.isSelected());\r
- }\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- * @return {@inheritDoc}\r
- */\r
- @Override\r
- public String toString(){\r
- return this.context.toString();\r
- }\r
-\r
- }\r
-\r
-}\r
+/*
+ * Filter panel
+ *
+ * License : The MIT License
+ * Copyright(c) 2008 olyutorskii
+ */
+
+package jp.sfjp.jindolf.view;
+
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.SysEvent;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sourceforge.jindolf.corelib.EventFamily;
+import jp.sourceforge.jindolf.corelib.TalkType;
+
+/**
+ * 発言フィルタ GUI。
+ */
+@SuppressWarnings("serial")
+public class FilterPanel extends JDialog
+ implements ActionListener, TopicFilter{
+
+ private static final int COLS = 4;
+
+
+ private final JCheckBox checkPublic = new JCheckBox("公開", true);
+ private final JCheckBox checkWolf = new JCheckBox("狼", true);
+ private final JCheckBox checkPrivate = new JCheckBox("独り言", true);
+ private final JCheckBox checkGrave = new JCheckBox("墓下", true);
+ private final JCheckBox checkExtra = new JCheckBox("Extra", true);
+
+ private final JButton selAllButton = new JButton("全選択");
+ private final JButton selNoneButton = new JButton("全解除");
+ private final JButton negateButton = new JButton("反転");
+
+ private final JCheckBox checkRealtime =
+ new JCheckBox("リアルタイム更新", true);
+ private final JButton applyButton = new JButton("フィルタ適用");
+
+ private final Map<Avatar, JCheckBox> cbMap =
+ new HashMap<>();
+ private final List<JCheckBox> cbList = new LinkedList<>();
+
+ private final EventListenerList listeners = new EventListenerList();
+
+ /**
+ * 発言フィルタを生成する。
+ * @param owner フレームオーナー
+ */
+ @SuppressWarnings("LeakingThisInConstructor")
+ public FilterPanel(Frame owner){
+ super(owner);
+ setModal(false);
+
+ GUIUtils.modifyWindowAttributes(this, true, false, true);
+
+ JComponent topicPanel = createTopicPanel();
+ JComponent avatarPanel = createAvatarPanel();
+ JComponent buttonPanel = createButtonPanel();
+ JComponent bottomPanel = createBottomPanel();
+ design(topicPanel, avatarPanel, buttonPanel, bottomPanel);
+
+ this.checkPublic.addActionListener(this);
+ this.checkWolf.addActionListener(this);
+ this.checkPrivate.addActionListener(this);
+ this.checkGrave.addActionListener(this);
+ this.checkExtra.addActionListener(this);
+
+ for(JCheckBox avatarCheckBox : this.cbList){
+ avatarCheckBox.addActionListener(this);
+ }
+
+ this.selAllButton.addActionListener(this);
+ this.selNoneButton.addActionListener(this);
+ this.negateButton.addActionListener(this);
+
+ this.checkRealtime.addActionListener(this);
+ this.applyButton.addActionListener(this);
+ this.applyButton.setEnabled(false);
+
+ return;
+ }
+
+ /**
+ * レイアウトデザインを行う。
+ * @param topicPanel システムイベント選択
+ * @param avatarPanel キャラ一覧
+ * @param buttonPanel ボタン群
+ * @param bottomPanel 下段パネル
+ */
+ private void design(JComponent topicPanel,
+ JComponent avatarPanel,
+ JComponent buttonPanel,
+ JComponent bottomPanel ){
+ Container content = getContentPane();
+
+ GridBagLayout layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ content.setLayout(layout);
+
+ constraints.weightx = 1.0 / 5;
+ constraints.weighty = 1.0;
+ constraints.gridheight = 3;
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.anchor = GridBagConstraints.CENTER;
+ content.add(topicPanel, constraints);
+
+ constraints.weightx = 0.0;
+ constraints.fill = GridBagConstraints.VERTICAL;
+ constraints.insets = new Insets(3, 0, 3, 0);
+ content.add(new JSeparator(SwingConstants.VERTICAL), constraints);
+
+ constraints.weightx = 4.0 / 5;
+ constraints.weighty = 0.0;
+ constraints.gridheight = 1;
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.insets = new Insets(0, 0, 0, 0);
+ content.add(buttonPanel, constraints);
+
+ constraints.insets = new Insets(0, 3, 0, 3);
+ content.add(new JSeparator(), constraints);
+
+ constraints.weighty = 1.0;
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.insets = new Insets(0, 0, 0, 0);
+ content.add(avatarPanel, constraints);
+
+ constraints.weightx = 1.0;
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ content.add(new JSeparator(SwingConstants.HORIZONTAL), constraints);
+
+ constraints.fill = GridBagConstraints.NONE;
+ constraints.anchor = GridBagConstraints.NORTHEAST;
+ content.add(bottomPanel, constraints);
+
+ return;
+ }
+
+ /**
+ * システムイベントチェックボックス群パネルを作成。
+ * @return システムイベントチェックボックス群パネル
+ */
+ private JComponent createTopicPanel(){
+ this.checkPublic.setToolTipText("誰にでも見える発言");
+ this.checkWolf.setToolTipText("人狼同士にしか見えない発言");
+ this.checkPrivate.setToolTipText("本人にしか見えない発言");
+ this.checkGrave.setToolTipText("死者同士にしか見えない発言");
+ this.checkExtra.setToolTipText("占い先や護衛先などのシステムメッセージ");
+
+ JPanel topicPanel = new JPanel();
+
+ Border border = BorderFactory.createEmptyBorder(2, 2, 2, 2);
+ topicPanel.setBorder(border);
+
+ GridBagLayout layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ topicPanel.setLayout(layout);
+
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.weightx = 1.0;
+ constraints.weighty = 1.0;
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ topicPanel.add(this.checkPublic, constraints);
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ topicPanel.add(this.checkWolf, constraints);
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ topicPanel.add(this.checkPrivate, constraints);
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ topicPanel.add(this.checkGrave, constraints);
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ topicPanel.add(this.checkExtra, constraints);
+
+ return topicPanel;
+ }
+
+ /**
+ * キャラ一覧チェックボックス群パネルを作成。
+ * @return キャラ一覧チェックボックス群パネル
+ */
+ private JComponent createAvatarPanel(){
+ JPanel avatarPanel = new JPanel();
+
+ Border border = BorderFactory.createEmptyBorder(2, 2, 2, 2);
+ avatarPanel.setBorder(border);
+
+ GridBagLayout layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ avatarPanel.setLayout(layout);
+
+ constraints.weightx = 1.0 / COLS;
+ constraints.weighty = 1.0;
+ constraints.anchor = GridBagConstraints.WEST;
+
+ int xPos = 0;
+ for(Avatar avatar : Avatar.getPredefinedAvatarList()){
+ JCheckBox checkBox = new JCheckBox(avatar.getName(), true);
+ checkBox.setToolTipText(avatar.getJobTitle());
+ this.cbList.add(checkBox);
+ if(xPos >= COLS - 1){
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ xPos = 0;
+ }else{
+ constraints.gridwidth = 1;
+ xPos++;
+ }
+ avatarPanel.add(checkBox, constraints);
+ this.cbMap.put(avatar, checkBox);
+ }
+
+ return avatarPanel;
+ }
+
+ /**
+ * ボタン群パネルを生成。
+ * @return ボタン群パネル
+ */
+ private JComponent createButtonPanel(){
+ this.selAllButton.setToolTipText(
+ "全キャラクタの発言を表示する");
+ this.selNoneButton.setToolTipText(
+ "全キャラクタの発言をフィルタリングする");
+ this.negateButton.setToolTipText(
+ "(表示⇔フィルタリング)の設定を反転させる");
+
+ JPanel buttonPanel = new JPanel();
+
+ GridBagLayout layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ buttonPanel.setLayout(layout);
+
+ constraints.weightx = 1.0 / 3;
+ constraints.insets = new Insets(3, 3, 3, 3);
+ buttonPanel.add(this.selAllButton, constraints);
+ buttonPanel.add(this.selNoneButton, constraints);
+ buttonPanel.add(this.negateButton, constraints);
+
+ return buttonPanel;
+ }
+
+ /**
+ * 下段パネルを生成する。
+ * @return 下段パネル
+ */
+ private JComponent createBottomPanel(){
+ JPanel panel = new JPanel();
+
+ GridBagLayout layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ panel.setLayout(layout);
+
+ constraints.fill = GridBagConstraints.NONE;
+ constraints.insets = new Insets(3, 3, 3, 3);
+ panel.add(this.checkRealtime, constraints);
+ panel.add(this.applyButton, constraints);
+
+ return panel;
+ }
+
+ /**
+ * リスナを登録する。
+ * @param listener リスナ
+ */
+ public void addChangeListener(ChangeListener listener){
+ this.listeners.add(ChangeListener.class, listener);
+ }
+
+ /**
+ * リスナを削除する。
+ * @param listener リスナ
+ */
+ public void removeChangeListener(ChangeListener listener){
+ this.listeners.remove(ChangeListener.class, listener);
+ }
+
+ /**
+ * 全リスナを取得する。
+ * @return リスナの配列
+ */
+ public ChangeListener[] getChangeListeners(){
+ return this.listeners.getListeners(ChangeListener.class);
+ }
+
+ /**
+ * 全リスナへフィルタ操作を通知する。
+ */
+ protected void fireCheckChanged(){
+ ChangeEvent changeEvent = new ChangeEvent(this);
+ for(ChangeListener listener : getChangeListeners()){
+ listener.stateChanged(changeEvent);
+ }
+ }
+
+ /**
+ * ボタン状態の初期化。
+ */
+ public void initButtons(){
+ this.checkPublic.setSelected(true);
+ this.checkWolf.setSelected(true);
+ this.checkPrivate.setSelected(true);
+ this.checkGrave.setSelected(true);
+ this.checkExtra.setSelected(true);
+
+ this.selAllButton.doClick();
+
+ return;
+ }
+
+ /**
+ * チェックボックスまたはボタン操作時にリスナとして呼ばれる。
+ * {@inheritDoc}
+ * @param event イベント
+ */
+ @Override
+ public void actionPerformed(ActionEvent event){
+ Object source = event.getSource();
+
+ boolean isRealtime = this.checkRealtime.isSelected();
+
+ if(source == this.selAllButton){
+ boolean hasChanged = false;
+ for(JCheckBox avatarCBox : this.cbList){
+ if( ! avatarCBox.isSelected()){
+ avatarCBox.setSelected(true);
+ hasChanged = true;
+ }
+ }
+ if(isRealtime && hasChanged){
+ fireCheckChanged();
+ }
+ }else if(source == this.selNoneButton){
+ boolean hasChanged = false;
+ for(JCheckBox avatarCBox : this.cbList){
+ if(avatarCBox.isSelected()){
+ avatarCBox.setSelected(false);
+ hasChanged = true;
+ }
+ }
+ if(isRealtime && hasChanged){
+ fireCheckChanged();
+ }
+ }else if(source == this.negateButton){
+ for(JCheckBox avatarCBox : this.cbList){
+ if(avatarCBox.isSelected()){
+ avatarCBox.setSelected(false);
+ }else{
+ avatarCBox.setSelected(true);
+ }
+ }
+ if(isRealtime){
+ fireCheckChanged();
+ }
+ }else if(source == this.checkRealtime){
+ if(isRealtime){
+ this.applyButton.setEnabled(false);
+ fireCheckChanged();
+ }else{
+ this.applyButton.setEnabled(true);
+ }
+ }else if(source == this.applyButton){
+ fireCheckChanged();
+ }else if(source instanceof JCheckBox){
+ if(isRealtime){
+ fireCheckChanged();
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param topic {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public boolean isFiltered(Topic topic){
+ Talk talk;
+ if(topic instanceof Talk){
+ talk = (Talk) topic;
+ }else if(topic instanceof SysEvent){
+ SysEvent sysEvent = (SysEvent) topic;
+ if(sysEvent.getEventFamily() == EventFamily.EXTRA){
+ if( ! this.checkExtra.isSelected() ){
+ return true;
+ }
+ }
+ return false;
+ }else{
+ return false;
+ }
+
+ JCheckBox cbox;
+
+ TalkType type = talk.getTalkType();
+ switch(type){
+ case PUBLIC:
+ cbox = this.checkPublic;
+ break;
+ case WOLFONLY:
+ cbox = this.checkWolf;
+ break;
+ case PRIVATE:
+ cbox = this.checkPrivate;
+ break;
+ case GRAVE:
+ cbox = this.checkGrave;
+ break;
+ default:
+ assert false;
+ return true;
+ }
+ if( ! cbox.isSelected()){
+ return true;
+ }
+
+ Avatar avatar = talk.getAvatar();
+ cbox = this.cbMap.get(avatar);
+ if( cbox != null && ! cbox.isSelected()){
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public FilterContext getFilterContext(){
+ return new FilterPanelContext();
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param context {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public boolean isSame(FilterContext context){
+ if(context == null) return false;
+ if( ! (context instanceof FilterPanelContext) ) return false;
+ FilterPanelContext argContext = (FilterPanelContext) context;
+ FilterPanelContext thisContext =
+ (FilterPanelContext) getFilterContext();
+
+ return thisContext.context.equals(argContext.context);
+ }
+
+ /**
+ * カスタム化されたフィルタ状態。
+ */
+ private final class FilterPanelContext implements FilterContext{
+
+ private final BitSet context = new BitSet();
+
+ /**
+ * コンストラクタ。
+ */
+ public FilterPanelContext(){
+ super();
+
+ int index = 0;
+ this.context.set(index++,
+ FilterPanel.this.checkPublic.isSelected());
+ this.context.set(index++,
+ FilterPanel.this.checkWolf.isSelected());
+ this.context.set(index++,
+ FilterPanel.this.checkPrivate.isSelected());
+ this.context.set(index++,
+ FilterPanel.this.checkGrave.isSelected());
+ this.context.set(index++,
+ FilterPanel.this.checkExtra.isSelected());
+
+ for(Avatar avatar : Avatar.getPredefinedAvatarList()){
+ JCheckBox checkBox = FilterPanel.this.cbMap.get(avatar);
+ this.context.set(index++, checkBox.isSelected());
+ }
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public String toString(){
+ return this.context.toString();
+ }
+
+ }
+
+}