package org.rr.commons.swing.components; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Set; import javax.swing.DefaultComboBoxModel; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.border.EmptyBorder; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import net.miginfocom.swing.MigLayout; import org.rr.commons.swing.components.model.DefaultJRCheckBoxComboBoxModel; import org.rr.commons.swing.components.model.JRCheckBoxComboBoxModel; public class JRCheckBoxComboBox<E> extends JRComboBox<E> { public static enum CheckState { NONE, ALL, MULTIPLE; } private CharSequence textForNone = ""; private CharSequence textForAll = "***"; private CharSequence textForMultiple = "..."; private JRCheckBoxComboBoxModel<E> model; private int minPopupWidth = -1; public JRCheckBoxComboBox() { super(); initialize(); } private void initialize() { this.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { JComboBox<E> box = JRCheckBoxComboBox.this; Object comp = box.getUI().getAccessibleChild(box, 0); if (comp instanceof JPopupMenu) { preparePopup((JPopupMenu) comp); } } private void preparePopup(JPopupMenu popup) { JRCheckBoxComboBoxModel<E> model = getJRCheckBoxComboBoxModel(); int popupHeight = model.getSize() * 10; popup.removeAll(); popup.setPopupSize(getSize().width, popupHeight); popup.setLightWeightPopupEnabled(false); popup.setLayout(new BorderLayout()); JPanel panel = new JPanel(new MigLayout()); panel.setOpaque(false); JScrollPane scrollPane = new JRScrollPane(panel); for (int i = 0; i < model.getSize(); i++) { String label = model.getLabel(i); boolean checked = model.isChecked(i); JCheckBox checkBox = new JCheckBox(label, checked); checkBox.setOpaque(false); checkBox.setName(String.valueOf(i)); panel.add(checkBox, "wrap"); checkBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { int index = Integer.valueOf(((JCheckBox)e.getSource()).getName()); if(e.getStateChange() == ItemEvent.SELECTED) { getJRCheckBoxComboBoxModel().setChecked(index, true); } else { getJRCheckBoxComboBoxModel().setChecked(index, false); } JRCheckBoxComboBox.this.repaint(); } }); popup.setPopupSize(Math.max( Math.max(popup.getPreferredSize().width, checkBox.getPreferredSize().width + scrollPane.getVerticalScrollBar().getSize().width), minPopupWidth), popupHeight); } scrollPane.getVerticalScrollBar().setUnitIncrement(10); scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0)); popup.add(scrollPane, BorderLayout.CENTER); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } @Override public void popupMenuCanceled(PopupMenuEvent e) { } }); this.setRenderer(new ListCellRenderer<E>() { JLabel label; { label = new JLabel(); label.setBorder(new EmptyBorder(0, 2, 0, 0)); } @Override public Component getListCellRendererComponent(JList<? extends E> list, E value, int index, boolean isSelected, boolean cellHasFocus) { JRCheckBoxComboBoxModel<E> model = getJRCheckBoxComboBoxModel(); if(model.getCheckCount() == 0) { label.setText(String.valueOf(textForNone)); } else if(model.getCheckCount() > 1) { label.setText(String.valueOf(textForMultiple)); } else if(model.getCheckCount() == model.getSize()) { label.setText(String.valueOf(textForAll)); } else { Set<Integer> checkedIndices = model.getCheckedIndices(); String labelText = model.getLabel(checkedIndices.iterator().next()); label.setText(labelText); } return label; } }); } public JRCheckBoxComboBoxModel<E> getCheckBoxComboBoxModel() { if(model ==null) { model = new DefaultJRCheckBoxComboBoxModel<E>(new ArrayList<E>(), null); } return model; } public void setCheckBoxComboBoxModel(JRCheckBoxComboBoxModel<E> aModel) { this.model = aModel; super.setModel(new DefaultComboBoxModel<E>() { @Override public int getSize() { return model.getSize(); } @Override public E getElementAt(int index) { return model.getValueAt(index); } @Override public Object getSelectedItem() { return null; } }); } public JRCheckBoxComboBoxModel<E> getJRCheckBoxComboBoxModel() { return this.model; } public void setTextFor(CheckState checkState, CharSequence text) { if(checkState == CheckState.ALL) { textForAll = text; } else if(checkState == CheckState.NONE) { textForNone = text; } else if(checkState == CheckState.MULTIPLE) { textForMultiple = text; } } public int getMinPopupWidth() { return minPopupWidth; } public void setMinPopupWidth(int minPopupWidth) { this.minPopupWidth = minPopupWidth; } }