![JAR search and dependency download from the Maven repository](/logo.png)
net.sf.cuf.ui.table.VisibilityDialog Maven / Gradle / Ivy
package net.sf.cuf.ui.table;
import net.sf.cuf.ui.SwingDecorator;
import java.awt.Component;
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.table.TableModel;
/**
* A modal visibility dialog for a table.
* The dialog allows to show and hide columns in a table.
* The user may choose from all the columns present in the table model.
*
* 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 VisibilityDialog extends BasicDialog
{
/** List box of column headers. */
private JList mColumnHeaders;
private boolean[] mResult;
/**
* Constructor.
* @param pOwner parent window (must not be null
)
*/
public VisibilityDialog(final Frame pOwner)
{
super(pOwner, "TABLEVIS_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
* - 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
* - double clicking on the list toggles the respective list entry
* - {@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 insetsList = new Insets(2, 4, 2, 4);
Insets insetsManipulationButtons = new Insets(2, 10, 2, 4);
Insets insetsButtons = new Insets(15, 4, 2, 4);
// add list to display the column visibility
mColumnHeaders = new JList();
mColumnHeaders.setCellRenderer(new ColumnListCellRenderer());
mColumnHeaders.addMouseListener(new MouseAdapter()
{
public void mouseClicked(final MouseEvent pEvent)
{
if (pEvent.getClickCount() == 2 && pEvent.getModifiers() == MouseEvent.BUTTON1_MASK)
{
processColumnToggle(mColumnHeaders.locationToIndex(pEvent.getPoint()));
pEvent.consume();
}
else
{
super.mouseClicked(pEvent);
}
}
});
gbc.gridheight = 4;
gbc.insets = insetsList;
pane.add(new JScrollPane(mColumnHeaders,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), gbc);
gbc.gridheight = 1;
// add list manipulation buttons
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = insetsManipulationButtons;
JButton buttonShow = new JButton();
SwingDecorator.initialize(buttonShow, "TABLEVIS_DIALOG_SHOW");
buttonShow.setDefaultCapable(false);
buttonShow.addActionListener(pEvent -> processColumnsShowHide(true));
gbc.gridx = 1;
pane.add(buttonShow, gbc);
JButton buttonHide = new JButton();
SwingDecorator.initialize(buttonHide, "TABLEVIS_DIALOG_HIDE");
buttonHide.setDefaultCapable(false);
buttonHide.addActionListener(pEvent -> processColumnsShowHide(false));
gbc.gridy++;
gbc.weighty = 100;
gbc.anchor = GridBagConstraints.NORTHWEST;
pane.add(buttonHide, gbc);
gbc.weighty = 0;
gbc.anchor = GridBagConstraints.WEST;
JButton buttonSelectAll = new JButton();
SwingDecorator.initialize(buttonSelectAll, "TABLEVIS_DIALOG_SELECTALL");
buttonSelectAll.setDefaultCapable(false);
buttonSelectAll.addActionListener(pEvent -> {
// select all list entries
mColumnHeaders.setSelectionInterval(0, mColumnHeaders.getModel().getSize() - 1);
});
gbc.gridy++;
pane.add(buttonSelectAll, gbc);
JButton buttonSelectNone = new JButton();
SwingDecorator.initialize(buttonSelectNone, "TABLEVIS_DIALOG_SELECTNONE");
buttonSelectNone.setDefaultCapable(false);
buttonSelectNone.addActionListener(pEvent -> {
// clear any selection
mColumnHeaders.clearSelection();
});
gbc.gridy++;
pane.add(buttonSelectNone, gbc);
gbc.fill = GridBagConstraints.NONE;
gbc.gridy++;
// add OK and Cancel buttons
gbc.gridx = 0;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.SOUTHEAST;
gbc.insets = insetsButtons;
pane.add(createOkCancelButtons(), gbc);
}
/**
* Show the modal dialog.
* This method blocks until all the user closes the dialog.
*
* The visibility is held in a boolean[]
. There must be an
* entry in this array for each table model column. true
* means the respective column is visible. false
makes the
* column hidden.
*
* @param pTableModel current table model (must not be null
)
* @param pVisible current visibility of the columns in the table (must not be null
)
* @return the selected visibility or null
if user cancelled the dialog
*/
public boolean[] show(final TableModel pTableModel, final boolean[] pVisible)
{
// check preconditions
if (pTableModel == null)
throw new IllegalArgumentException("tableModel must not be null");
if (pVisible == null)
throw new IllegalArgumentException("tableSortInfoList must not be null");
if (pTableModel.getColumnCount() != pVisible.length)
throw new IllegalArgumentException("tableModel and visibility must contain the same number of elements");
// initialize list
mColumnHeaders.setModel(new ColumnListModel(fetchColumnHeaders(pTableModel, 0), pVisible));
mColumnHeaders.setSelectionModel(new javax.swing.DefaultListSelectionModel()); // there is no other way to get rid of the focus on the last selected item
mColumnHeaders.ensureIndexIsVisible(0);
mColumnHeaders.requestFocus();
// show dialog
showDialog(); // will block until hide() gets called.
// return the result
return mResult;
}
/**
* Close the dialog and extract the result from the user input.
*/
protected void processDialogOk()
{
setVisible(false);
// set result
ColumnListModel columns = (ColumnListModel) mColumnHeaders.getModel();
mResult = new boolean[columns.getSize()];
for (int i = 0; i < columns.getSize(); i++)
{
mResult[i] = ((ColumnListElement) columns.getElementAt(i)).mVisible;
}
}
/**
* Close the dialog and clear the result.
*/
protected void processDialogCancel()
{
setVisible(false);
// set result
mResult = null; // no result
}
/**
* Change the visibility of all selected list entries.
* @param pShow true
if all selected entries are to be made visible
*/
private void processColumnsShowHide(final boolean pShow)
{
Object[] selected = mColumnHeaders.getSelectedValues();
for (final Object aSelected : selected)
{
((ColumnListElement) aSelected).mVisible = pShow;
}
((ColumnListModel) mColumnHeaders.getModel()).notifyListeners();
}
/**
* Toggle the visibility of a single list entry.
* @param pIndex index of the entry to be toggled
*/
private void processColumnToggle(final int pIndex)
{
if (pIndex != -1)
{
ColumnListElement elem = (ColumnListElement)(mColumnHeaders.getModel()).getElementAt(pIndex);
elem.mVisible = !elem.mVisible;
((ColumnListModel) mColumnHeaders.getModel()).notifyListeners(pIndex);
}
}
/**
* List model for our display of the table columns.
*
* It is the responsibility of the caller to trigger the notification of
* the listeners about any changes to the list model.
*/
private static class ColumnListModel
extends AbstractListModel
{
/** List of {@link ColumnListElement}s. */
private List mColumns;
/**
* Constructor.
* Initializes the list model with the given data.
* @param pHeaders list of column names
* @param pVisible list of visibility state of the columns
*/
public ColumnListModel(final Object[] pHeaders, final boolean[] pVisible)
{
int count = pHeaders.length;
mColumns = new ArrayList<>(count);
for (int i = 0; i < count; i++)
{
mColumns.add(new ColumnListElement(pHeaders[i].toString(), pVisible[i]));
}
}
public Object getElementAt(final int pIndex)
{
return mColumns.get(pIndex);
}
public int getSize()
{
return mColumns.size();
}
/**
* Notify the listeners that all the list elements have changed their values.
*/
public void notifyListeners()
{
fireContentsChanged(this, 0, getSize());
}
/**
* Notify the listeners that a specific list element has changed its value.
* @param pIndex the index that changed
*/
public void notifyListeners(final int pIndex)
{
fireContentsChanged(this, pIndex, pIndex);
}
}
/**
* Container for the information about one table column.
* The attributes in this data container are all public for ease of access.
*/
private static class ColumnListElement
{
/** Text to display as the column name. */
public String mName;
/** State associated with this column. */
public boolean mVisible;
public ColumnListElement(final String pName, final boolean pVisible)
{
mName = pName;
mVisible = pVisible;
}
public String toString()
{
return mName + " (" + (mVisible ?"":"in") + "visible)";
}
}
/**
* Cell renderer with visibility icon and column name.
* This cell renderer works with {@link ColumnListElement}s.
*
* This class extends {@link javax.swing.DefaultListCellRenderer} in order to profit from its performance optimizations.
*/
private static class ColumnListCellRenderer
extends DefaultListCellRenderer
{
/** Icon for visible columns. */
private static Icon sIconVisible = null;
/** Icon for invisible columns. */
private static Icon sIconInvisible = null;
/**
* Constructor.
*/
public ColumnListCellRenderer()
{
loadIcons();
setVerticalTextPosition(CENTER);
setHorizontalTextPosition(RIGHT);
}
/**
* Initialize the class attributes in a threadsafe manner.
* If the icons are already loaded this method does nothing.
*/
private static synchronized void loadIcons()
{
if (sIconVisible == null)
{
sIconVisible = SwingDecorator.getIcon("TABLEVIS_DIALOG_VISIBLE");
sIconInvisible = SwingDecorator.getIcon("TABLEVIS_DIALOG_INVISIBLE");
}
}
/**
* Set up a renderer for a list entry.
* @return fully configured renderer for the given value
*/
public Component getListCellRendererComponent(final JList pList,
final Object pValue,
final int pIndex,
final boolean pIsSelected,
final boolean pCellHasFocus)
{
// this code is modeled after the SwingSet demo for JListBox in the Java 2 SDK
ColumnListElement elem = (ColumnListElement) pValue;
super.getListCellRendererComponent(pList, elem.mName, pIndex, pIsSelected, pCellHasFocus); // just let our ancestor configure this object
setIcon(elem.mVisible ? sIconVisible : sIconInvisible);
return this;
}
}
}