package com.onaro.util.jfc.tables.filter; import java.awt.EventQueue; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Set; import java.util.TreeSet; import javax.swing.JComboBox; import javax.swing.table.TableModel; import org.apache.commons.lang3.StringUtils; import com.onaro.util.jfc.EnumJComboBox; import com.onaro.util.jfc.tables.FilterTable; /** * A filter editor displas a border-less popup window containig a text field in which the user types the search pattern. * The editor is closed whenever the table or the window changes or the mouse is clicked outside the editor. */ public class EnumComboBoxFilterEditor extends AbstractFilterEditor implements ActionListener{ /** * Installs a borderless pop up window on top a column's header and configures the listeners needed to close * this popup. */ public EnumComboBoxFilterEditor(FilterTable filterTable, EnumFilter filter, int selectedColumnInModel) { super(filterTable, selectedColumnInModel, filter, new EnumJComboBox()); Set nonEnumValuesInQuery = collectAllNonEnumValuesInQuery(selectedColumnInModel, filter.getAttributesSet()); EnumJComboBox comboBox = ((EnumJComboBox) field); comboBox.setValues(filter.getAttributes(), nonEnumValuesInQuery, filter.getPattern()); comboBox.addActionListener(this); comboBox.setEditable(false); comboBox.addPopupMenuListener(this); } protected Set collectAllNonEnumValuesInQuery(int selectedColumnInModel, Set attributes) { //the values should be sorted by their lexicographic order - which is the default Set set = new TreeSet(); TableModel model = filterTable.getFilterModel().getEncapsulatedTableModel(); int rows = model.getRowCount(); for (int i = 0; i < rows; i++) { Object valueAt = model.getValueAt(i, selectedColumnInModel); //add only if value is not an enum (which are listed in the EnumFilter) or the same as the enum name if (valueAt != null && StringUtils.isNotBlank(valueAt.toString()) && !attributes.contains(valueAt) && !attributes.contains(valueAt.toString().toLowerCase())) { set.add(valueAt); } } return set; } public Object getPattern() { EnumJComboBox comboBox = ((EnumJComboBox) field); return comboBox.getSelectedValue(); } protected void hideLater(AbstractFilterEditor filterEditor) { @SuppressWarnings("unchecked") JComboBox comboBox = ((JComboBox) field); comboBox.setPopupVisible(false); comboBox.removeActionListener(this); super.hideLater(filterEditor); } public void show(Rectangle headerRect) { super.show(headerRect); //make sure that the combo box will be opened after the pop up is shown //if invoke later is not used, the setting will have no effect since is it still not shown final EnumJComboBox comboBox = ((EnumJComboBox) field); EventQueue.invokeLater(new Runnable() { public void run() { comboBox.setPopupVisible(true); } }); } /** * Invoked when an action occurs.
* There is an interesting behaviour that we want to achive in this class. * As a result of implementing Customer Case #3509 we introduce autocompletion. * If there are 2 or more options that share the same initial sequence of letters we want to * highlight the first option matching user's input, but without closing the combo-box, this will allow the user to * see the remaining options so he/she can continue typing and looking the next remaining matching options. * Once the user is satisfied with the selected item he/she will press ENTER key triggering the closing of the * combo-box and the underline processing. * */ public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("comboBoxChanged")){ //$NON-NLS-1$ // Dismiss this event so the combo-box remains open until the user presses ENTER key // or select the combo-box's item using a mouse-click-event. return; } // Any other event proceeed closing the combo-box. close(true); } }