All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.cuf.ui.table.SortDialog Maven / Gradle / Ivy

The newest version!
package net.sf.cuf.ui.table;

import net.sf.cuf.ui.SwingDecorator;

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.awt.event.KeyEvent;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JRootPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;


/**
 * A modal sorting dialog for a table.
 * The dialog allows the selection of sorting criteria for a table.
 * Several sorting criteria may be selected by the user.
 * The user may choose from all currently visible columns.
 * 

* The dialog will be centered over the parent window the first time it is opened. * Later on it will keep its last position. * * @author Hendrik Wördehoff, sd&m AG */ public class SortDialog extends BasicDialog { /** Number of supported sort criteria. */ private static final int CRITERIA_COUNT = 3; /** Number of additional entries for column headers. Currently only empty string. */ private static final int COLUMN_HEADER_OFFSET = 1; /** List of combo boxes for the sort criteria. */ private JComboBox[] mCriteria; /** List of radio buttons for the sorting direction. */ private JRadioButton[] mAscending; /** List of radio buttons for the sorting direction. */ private JRadioButton[] mDescending; /** * Reference to the table we are working for. * This attribute is only valid during {@link #show(JTable,TableSortInfo)}. */ private JTable mCurrentTable = null; /** * Result of showing the dialog. */ private TableSortInfo mResult; /** * Constructor. * @param pOwner parent window (must not be null) */ public SortDialog(final Frame pOwner) { super(pOwner, "TABLESORT_DIALOG"); addComponents(); } /** * Create all the components of the dialog. *

* The dialog features the following interesting points: *

    *
  • the OK button acts as the default button and can be activated with the ENTER key
  • *
  • in order to get the default button working properly the keyboard action on ENTER of the combo boxes has to be removed
  • *
  • the default button behaviour has to be modified to resolve conflicts with combo box popups
  • *
  • Cancel becomes default button when it gets the focus so the default button has to be reset to OK as soon as the focus moves away
  • *
  • the focus sequence has to be set manually
  • *
  • {@link net.sf.cuf.ui.SwingDecorator} is used for initialising the components
  • *
*/ private void addComponents() { // define layout Container pane = getContentPane(); pane.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridy = 0; gbc.anchor = GridBagConstraints.WEST; gbc.gridwidth = 1; gbc.gridheight = 1; gbc.ipadx = 0; gbc.ipady = 0; Insets insetsLabel = new Insets(2, 4, 2, 4); Insets insetsCombo = new Insets(2, 4, 2, 4); Insets insetsRadio = new Insets(2, 10, 2, 4); Insets insetsButtons = new Insets(15, 4, 2, 4); // add combo boxes to choose selection criteria mCriteria = new JComboBox [CRITERIA_COUNT]; mAscending = new JRadioButton[CRITERIA_COUNT]; mDescending = new JRadioButton[CRITERIA_COUNT]; for (int i = 0; i < CRITERIA_COUNT; i++) { JLabel l = new JLabel(); SwingDecorator.initialize(l,"TABLESORT_DIALOG_CRITERIA" + (i + 1)); gbc.gridx = 0; gbc.insets = insetsLabel; pane.add(l, gbc); mCriteria[i] = new JComboBox(); // combo box model will be set later SwingDecorator.initialize(mCriteria[i], "TABLESORT_DIALOG_CRITERIAINPUT" + (i + 1)); // set tool tip mCriteria[i].unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); // let the ENTER key trigger the default button gbc.gridx = 1; gbc.insets = insetsCombo; pane.add(mCriteria[i], gbc); Box box = Box.createVerticalBox(); gbc.gridx = 2; gbc.insets = insetsRadio; pane.add(box, gbc); ButtonGroup bg = new ButtonGroup(); mAscending[i] = new JRadioButton(); SwingDecorator.initialize(mAscending[i], "TABLESORT_DIALOG_ASCENDING"); box.add(mAscending[i]); bg.add(mAscending[i]); box.add(Box.createVerticalStrut(-3)); // reduce gap between the radio buttons; if they get any nearer the focus frame will be cut off unter Metal L&F mDescending[i] = new JRadioButton(); SwingDecorator.initialize(mDescending[i], "TABLESORT_DIALOG_DESCENDING"); box.add(mDescending[i]); bg.add(mDescending[i]); gbc.gridy++; } // add OK and Cancel buttons gbc.gridx = 0; gbc.gridwidth = 3; gbc.anchor = GridBagConstraints.SOUTHEAST; gbc.insets = insetsButtons; pane.add(createOkCancelButtons(), gbc); // resolve conflicts between default button and combo boxes JRootPane root = getRootPane(); KeyStroke k1 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false); KeyStroke k2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true); ActionListener a1 = root.getActionForKeyStroke(k1); ActionListener a2 = root.getActionForKeyStroke(k2); root.unregisterKeyboardAction(k1); root.unregisterKeyboardAction(k2); root.registerKeyboardAction(new FilteredAction(a1), k1, JComponent.WHEN_IN_FOCUSED_WINDOW); root.registerKeyboardAction(new FilteredAction(a2), k2, JComponent.WHEN_IN_FOCUSED_WINDOW); } /** * Show the modal dialog. * This method blocks until all the user closes the dialog. *

* We need a reference to the table in order to determine the visible * columns and to convert between model and view column indizes. * @param pTable current table (must not be null) * @param pSortInfo current sorting in the table (must not be null) * @return the selected ordering or null, if user cancelled dialog */ public TableSortInfo show(final JTable pTable, final TableSortInfo pSortInfo) { // check preconditions if (pTable == null) throw new IllegalArgumentException("table must not be null"); if (pSortInfo == null) throw new IllegalArgumentException("tableSortInfoList must not be null"); // fill lists in combo boxes Object[] headers = fetchVisibleColumnHeaders(pTable.getColumnModel(), COLUMN_HEADER_OFFSET); for (int i = 0; i < CRITERIA_COUNT; i++) { mCriteria[i].setModel(new DefaultComboBoxModel(headers)); } // initialize components with respect to current sorting info initializeComponents(pTable, pSortInfo); mCriteria[0].requestFocus(); // show dialog mCurrentTable = pTable; showDialog(); // will block until hide() gets called. mCurrentTable = null; // return the result return mResult; } /** * Initialize components of dialog with respect to current tableSortInfoList. * @param pTable current table * @param pSortInfo current sorting information */ private void initializeComponents(final JTable pTable, final TableSortInfo pSortInfo) { // Number of Components to initialize int numInitialize = Math.min(CRITERIA_COUNT, pSortInfo.size()); for (int i = 0; i < CRITERIA_COUNT; i++) { int sel = 0; boolean asc = true; if ( i < numInitialize ) // we use the above values for any additional sorting criteria in the dialog { // we have to convert the model index from the sort info to a view index // we have to add an offset because the first entries in criteria-ComboBox are empty Strings sel = pTable.convertColumnIndexToView(pSortInfo.getColumn(i)) + COLUMN_HEADER_OFFSET; asc = pSortInfo.isAscending(i); } mCriteria[i].setSelectedIndex(sel); mAscending[i].setSelected(asc); mDescending[i].setSelected(!asc); } } /** * Close the dialog and extract the result from the user input. */ protected void processDialogOk() { setVisible(false); // set result mResult = new TableSortInfo(); for (int i = 0; i < CRITERIA_COUNT; i++) { int selectedIndex = mCriteria[i].getSelectedIndex(); if (selectedIndex >= COLUMN_HEADER_OFFSET) { mResult.sortByColumn(mCurrentTable.convertColumnIndexToModel(selectedIndex - COLUMN_HEADER_OFFSET), mAscending[i].isSelected()); } } } /** * Close the dialog and clear the result. */ protected void processDialogCancel() { setVisible(false); // set no result mResult = null; } /** * Helper class to filter actions. * It only processes the actions if all popups from the combo boxes are closed. *

* We use this to filter the activation of the default button with ENTER. * Otherwise there would be conflicts with the popups of the combo boxes * which react on the ENTER key as well. */ protected class FilteredAction implements ActionListener { /** Action to perform. */ private ActionListener mAction; /** * Constructor. * @param pAction action to perform */ public FilteredAction(final ActionListener pAction) { this.mAction = pAction; } /** * Perform the filtering on the action. * @param pEvent action event */ public void actionPerformed(final ActionEvent pEvent) { if (!isAnyComboBoxPopupVisible()) { mAction.actionPerformed(pEvent); } } /** * Determine if any of the combo box popups are open. * @return true on any open popup */ public boolean isAnyComboBoxPopupVisible() { boolean res = false; for (int i = 0; i < CRITERIA_COUNT; i++) { res |= mCriteria[i].isPopupVisible(); } return res; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy