package com.subhajit.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import com.subhajit.common.util.StrUtils;
import com.subhajit.gui.form.beaneditor.annotations.MaxWidth;
public class GuiUtils {
public static class ComponentCreator {
public static final JComponent newComponent(
Class<? extends JComponent> klass) {
try {
JComponent ret = (JComponent) klass.newInstance();
ret.invalidate();
ret.setVisible(true);
return ret;
} catch (Exception exc) {
throw new RuntimeException(StrUtils.toString(exc));
}
}
public static JButton newButton() {
return (JButton) GuiUtils.ComponentCreator
.newComponent(JButton.class);
}
public static JButton newButton(String text) {
JButton ret = (JButton) GuiUtils.ComponentCreator
.newComponent(JButton.class);
ret.setText(text);
return ret;
}
public static JButton newButton(String text, String tooltipText) {
JButton ret = (JButton) GuiUtils.ComponentCreator
.newComponent(JButton.class);
ret.setText(text);
ret.setToolTipText(tooltipText);
return ret;
}
public static JTextField newTextField(int... dims) {
JTextField component = (JTextField) ComponentCreator
.newComponent(JTextField.class);
resizeComponent(component, dims);
return component;
}
public static JTextArea newTextArea() {
return (JTextArea) ComponentCreator.newComponent(JTextArea.class);
}
public static JLabel newLabel() {
return (JLabel) ComponentCreator.newComponent(JLabel.class);
}
public static JLabel newLabel(String text, int... dims) {
JLabel label = (JLabel) ComponentCreator.newComponent(JLabel.class);
label.setVerticalAlignment(SwingConstants.CENTER);
label.setText(text);
// label.setBorder(new LineBorder(Color.red));
resizeComponent(label, dims);
return label;
}
private static void resizeComponent(JComponent component, int... dims) {
if (dims != null) {
if (dims.length >= 2) {
component.setMinimumSize(new Dimension(dims[0], dims[1]));
component.setPreferredSize(new Dimension(dims[0], dims[1]));
component.setMaximumSize(new Dimension(dims[0], dims[1]));
} else if (dims.length == 1) {
GuiUtils.setComponentWidth(component, dims[0]);
}
}
}
public static JCheckBox newCheckBox() {
return (JCheckBox) ComponentCreator.newComponent(JCheckBox.class);
}
public static JList newListBox() {
return (JList) ComponentCreator.newComponent(JList.class);
}
public static JComboBox newComboBox() {
JComboBox ret = (JComboBox) ComponentCreator
.newComponent(JComboBox.class);
DefaultComboBoxModel model = new DefaultComboBoxModel();
ret.setModel(model);
return ret;
}
public static JComboBox newComboBox(Object[] options) {
JComboBox ret = (JComboBox) ComponentCreator
.newComponent(JComboBox.class);
DefaultComboBoxModel model = new DefaultComboBoxModel(options);
ret.setModel(model);
return ret;
}
public static JPasswordField newPasswordField(int... dims) {
JPasswordField component = (JPasswordField) ComponentCreator
.newComponent(JPasswordField.class);
resizeComponent(component, dims);
return component;
}
public static JPanel newPanel() {
return (JPanel) ComponentCreator.newComponent(JPanel.class);
}
public static class ExtendedTable extends JTable {
private static final long serialVersionUID = 1L;
private int editableRow = -1, editableColumn = -1;
public ExtendedTable() {
super();
}
public ExtendedTable(int numRows, int numColumns) {
super(numRows, numColumns);
}
public ExtendedTable(Object[][] rowData, Object[] columnNames) {
super(rowData, columnNames);
}
public ExtendedTable(TableModel dm, TableColumnModel cm,
ListSelectionModel sm) {
super(dm, cm, sm);
}
public ExtendedTable(TableModel dm, TableColumnModel cm) {
super(dm, cm);
}
public ExtendedTable(TableModel dm) {
super(dm);
}
@SuppressWarnings("unchecked")
public ExtendedTable(Vector rowData, Vector columnNames) {
super(rowData, columnNames);
}
@Override
public boolean isCellEditable(int row, int column) {
if (row == editableRow && column == editableColumn) {
return true;
} else {
return false;
}
}
public int getEditableRow() {
return editableRow;
}
public void setEditableRow(int editableRow) {
this.editableRow = editableRow;
}
public int getEditableColumn() {
return editableColumn;
}
public void setEditableColumn(int editableColumn) {
this.editableColumn = editableColumn;
}
}
public static JTable newTable() {
JTable ret = new JTable() {
private static final long serialVersionUID = 1L;
public Component prepareRenderer(TableCellRenderer renderer,
int rowIndex, int vColIndex) {
Component c = super.prepareRenderer(renderer, rowIndex,
vColIndex);
if (c instanceof JComponent) {
JComponent jc = (JComponent) c;
jc.setToolTipText((String) getValueAt(rowIndex,
vColIndex));
}
return c;
}
};
ret.setModel(new DefaultTableModel());
ret.setVisible(true);
ret.invalidate();
return ret;
}
public static JTable newTable(final String[] tableLabels,
final int[] columnWidths) {
final JTable table = new ExtendedTable(new DefaultTableModel());
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setCellSelectionEnabled(false);
table.setColumnSelectionAllowed(true);
table.setRowSelectionAllowed(true);
table.setGridColor(Color.LIGHT_GRAY);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getTableHeader().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1
&& e.getButton() == MouseEvent.BUTTON1) {
final int column = table.getTableHeader()
.columnAtPoint(e.getPoint());
DefaultTableModel model = (DefaultTableModel) table
.getModel();
@SuppressWarnings("unchecked")
List<List<Object>> data = model.getDataVector();
Collections.sort(data, new Comparator<List<Object>>() {
public int compare(List<Object> o1, List<Object> o2) {
Object obj1 = o1.get(column);
Object obj2 = o2.get(column);
if (obj1 == null && obj2 == null) {
return 0;
} else if (obj1 == null && obj2 != null) {
return -1;
} else if (obj1 != null && obj2 == null) {
return 1;
} else {
if (Comparable.class.isAssignableFrom(obj1
.getClass())) {
@SuppressWarnings("unchecked")
Comparable<Object> comp1 = ((Comparable<Object>) obj1);
return comp1.compareTo(obj2);
} else {
return obj1.toString().compareTo(
obj2.toString());
}
}
}
});
model.fireTableDataChanged();
}
}
});
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setColumnCount(tableLabels.length);
model.setColumnIdentifiers(tableLabels);
for (int i = 0; i < columnWidths.length; i++) {
if (columnWidths[i] != -1) {
table.getColumnModel().getColumn(i).setPreferredWidth(
columnWidths[i]);
((TableColumnModel) table.getColumnModel())
.setColumnSelectionAllowed(true);
}
}
return table;
}
public static interface IToolTipGetter {
String valueAt(JTable table, int row, int column);
}
public static JTable newTable(IToolTipGetter toolTipGetter,
final String[] tableLabels, final int[] columnWidths) {
final JTable table = newTableWithToolTips(toolTipGetter);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setCellSelectionEnabled(false);
table.setColumnSelectionAllowed(true);
table.setRowSelectionAllowed(true);
table.setGridColor(Color.LIGHT_GRAY);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getTableHeader().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1
&& e.getButton() == MouseEvent.BUTTON1) {
final int column = table.getTableHeader().columnAtPoint(
e.getPoint());
DefaultTableModel model = (DefaultTableModel) table
.getModel();
@SuppressWarnings("unchecked")
List<List<Object>> data = model.getDataVector();
Collections.sort(data, new Comparator<List<Object>>() {
public int compare(List<Object> o1, List<Object> o2) {
Object obj1 = o1.get(column);
Object obj2 = o2.get(column);
if (obj1 == null && obj2 == null) {
return 0;
} else if (obj1 == null && obj2 != null) {
return -1;
} else if (obj1 != null && obj2 == null) {
return 1;
} else {
if (Comparable.class.isAssignableFrom(obj1
.getClass())) {
@SuppressWarnings("unchecked")
Comparable<Object> comp1 = ((Comparable<Object>) obj1);
return comp1.compareTo(obj2);
} else {
return obj1.toString().compareTo(
obj2.toString());
}
}
}
});
model.fireTableDataChanged();
}
}
});
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setColumnCount(tableLabels.length);
model.setColumnIdentifiers(tableLabels);
for (int i = 0; i < columnWidths.length; i++) {
if (columnWidths[i] != -1) {
table.getColumnModel().getColumn(i).setPreferredWidth(
columnWidths[i]);
((TableColumnModel) table.getColumnModel())
.setColumnSelectionAllowed(true);
}
}
return table;
}
private static final JTable newTableWithToolTips(final IToolTipGetter getter) {
return new JTable(new DefaultTableModel()) {
private static final long serialVersionUID = 1L;
@Override
public Component prepareRenderer(TableCellRenderer renderer,
int row, int column) {
Component component = super.prepareRenderer(renderer, row,
column);
if (component instanceof JComponent) {
JComponent jc = (JComponent) component;
jc.setToolTipText(getter.valueAt(this, row, column));
}
return component;
}
};
}
public static JTable newReadOnlyTable(final String[] tableLabels,
final int[] columnWidths) {
JTable table = new JTable(new DefaultTableModel() {
private static final long serialVersionUID = 1L;
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
});
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setCellSelectionEnabled(false);
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(true);
table.setGridColor(Color.LIGHT_GRAY);
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setColumnCount(tableLabels.length);
model.setColumnIdentifiers(tableLabels);
for (int i = 0; i < columnWidths.length; i++) {
if (columnWidths[i] != -1) {
table.getColumnModel().getColumn(i).setPreferredWidth(
columnWidths[i]);
}
}
return table;
}
public static JTable newTable(
final List<Map.Entry<String, Class<?>>> columns) {
return TableCreator.newTable(columns);
}
}
public static class GuiConstructionUtilities {
/**
* Private default constructor for utility class
*
*/
private GuiConstructionUtilities() {
super();
}
/**
* @return
*/
public static Box.Filler newHorizontalFiller(int dim) {
Dimension fillerDimension = new Dimension(dim, 5);
Box.Filler filler = new Box.Filler(fillerDimension,
fillerDimension, fillerDimension);
return filler;
}
/**
* @return
*/
public static Box.Filler newVerticalFiller(int dim) {
Dimension fillerDimension = new Dimension(5, dim);
Box.Filler filler = new Box.Filler(fillerDimension,
fillerDimension, fillerDimension);
return filler;
}
public static JPanel wrapComponentInBorderLayout(JComponent component,
String borderLayoutSpec) {
JPanel ret = new JPanel();
ret.setLayout(new BorderLayout());
if (component.getClass().getAnnotation(MaxWidth.class) != null) {
int maxWidth = component.getClass().getAnnotation(
MaxWidth.class).value();
JPanel northPanel = new JPanel();
northPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
GuiUtils.setComponentWidth(component, maxWidth);
northPanel.add(component);
northPanel.add(GuiUtils.GuiConstructionUtilities
.newHorizontalFiller(30));
ret.add(northPanel, borderLayoutSpec);
} else {
JPanel innerPanel = new JPanel();
innerPanel.setLayout(new BorderLayout());
innerPanel.add(GuiUtils.GuiConstructionUtilities
.newHorizontalFiller(5), BorderLayout.WEST);
innerPanel.add(component);
innerPanel.add(GuiUtils.GuiConstructionUtilities
.newHorizontalFiller(10), BorderLayout.EAST);
ret.add(innerPanel, borderLayoutSpec);
}
ret.invalidate();
ret.setVisible(true);
return ret;
}
public static JPanel createVerticallyStackedPanel(String[] labels,
JComponent[] components, Border border) {
JPanel ret = new JPanel();
ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
ret.setAlignmentY((float) 0);
for (int i = 0; i < labels.length; i++) {
// Create the label
JLabel label = new JLabel();
label.setText(labels[i]);
label.invalidate();
label.setVisible(true);
JPanel labelPanel = wrapComponentInBorderLayout(label,
BorderLayout.NORTH);
JPanel componentPanel = wrapComponentInBorderLayout(
components[i], BorderLayout.NORTH);
componentPanel.add(newVerticalFiller(10));
ret.add(labelPanel);
ret.add(componentPanel);
}
return wrapComponentInBorderLayout(ret, BorderLayout.NORTH);
}
public static JPanel createVerticallyStackedPanel(
JComponent[] components, int verticalgap) {
JPanel ret = new JPanel();
ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
ret.setAlignmentY((float) 0);
for (int i = 0; i < components.length; i++) {
JPanel componentPanel = wrapComponentInBorderLayout(
components[i], BorderLayout.NORTH);
componentPanel.add(newVerticalFiller(verticalgap));
ret.add(componentPanel);
}
return wrapComponentInBorderLayout(ret, BorderLayout.NORTH);
}
public static JPanel createVerticallyStackedPanel(String[] labels,
JComponent[] components, Border border, int componentWidth) {
JPanel ret = new JPanel();
ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
ret.setAlignmentY((float) 0);
for (int i = 0; i < labels.length; i++) {
// Create the label
JLabel label = new JLabel();
label.setText(labels[i]);
label.invalidate();
label.setVisible(true);
JPanel labelPanel = wrapComponentInBorderLayout(label,
BorderLayout.NORTH);
JPanel componentPanel = wrapComponentInBorderLayout(
components[i], BorderLayout.NORTH);
componentPanel.add(newVerticalFiller(10));
ret.add(labelPanel);
GuiUtils.setComponentWidth(componentPanel, componentWidth);
ret.add(componentPanel);
}
return wrapComponentInBorderLayout(ret, BorderLayout.NORTH);
}
public static JPanel wrapPanelInBorderLayoutPanel(JPanel panel) {
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(newHorizontalFiller(15), BorderLayout.WEST);
mainPanel.add(newHorizontalFiller(15), BorderLayout.EAST);
mainPanel.add(newVerticalFiller(15), BorderLayout.SOUTH);
mainPanel.add(panel);
return mainPanel;
}
/**
* Creates and returns a JPanel containing a set of vertically stacked
* components, each with a label.
*
* @param labels
* @param components
* @return
*/
public static JPanel createVerticallyStackedPanelWithEtchedBorderAroundComponents(
String[] labels, JComponent[] components) {
JPanel ret = new JPanel();
ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
ret.setAlignmentY((float) 0);
for (int i = 0; i < labels.length; i++) {
JPanel componentPanel = new JPanel();
componentPanel.invalidate();
componentPanel.setVisible(true);
componentPanel.setLayout(new GridLayout(1, 1));
componentPanel.setBorder(new TitledBorder(new EtchedBorder(),
labels[i]));
componentPanel.add(components[i]);
ret.add(componentPanel);
}
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(newHorizontalFiller(15), BorderLayout.WEST);
mainPanel.add(newHorizontalFiller(15), BorderLayout.EAST);
mainPanel.add(newVerticalFiller(15), BorderLayout.SOUTH);
mainPanel.add(ret);
return mainPanel;
}
public static JPanel createVerticallyStackedPanelWithEtchedBorderAroundComponents(
String[] labels, JComponent[] components, int componentWidth,
int componentHeight) {
JPanel ret = new JPanel();
ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
ret.setAlignmentY((float) 0);
for (int i = 0; i < labels.length; i++) {
JPanel componentPanel = new JPanel();
componentPanel.invalidate();
componentPanel.setVisible(true);
componentPanel.setLayout(new GridLayout(1, 1));
componentPanel.setBorder(new TitledBorder(new EtchedBorder(),
labels[i]));
componentPanel.add(components[i]);
GuiUtils.setComponentWidth(componentPanel, componentWidth);
GuiUtils.setComponentHeight(componentPanel, componentHeight);
ret.add(componentPanel);
}
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(newHorizontalFiller(15), BorderLayout.WEST);
mainPanel.add(newHorizontalFiller(15), BorderLayout.EAST);
mainPanel.add(newVerticalFiller(15), BorderLayout.SOUTH);
mainPanel.add(ret);
return mainPanel;
}
/**
* Creates and returns a panel containing two buttons, one labeled "Ok"
* and one labeled "Cancel". The buttons have the same dimensions, and
* are aligned along the right edge of the panel.
*
* @param controls
* @return
*/
public static JPanel createRightAlignedOkAndCancelButtonPanel(
Map<String, JButton> controls) {
JPanel panel = new JPanel();
panel.invalidate();
panel.setVisible(true);
panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
JButton ok = new JButton("Ok");
ok.invalidate();
ok.setVisible(true);
JButton cancel = new JButton("Cancel");
cancel.invalidate();
cancel.setVisible(true);
controls.put("ok", ok);
controls.put("cancel", cancel);
JPanel buttonsPanel = new JPanel();
buttonsPanel.invalidate();
buttonsPanel.setVisible(true);
buttonsPanel.setLayout(new GridLayout(1, 2, 10, 10));
buttonsPanel.add(ok);
buttonsPanel.add(cancel);
panel.add(buttonsPanel);
return wrapComponentInBorderLayout(panel, BorderLayout.SOUTH);
}
public static JPanel createRightAlignedButtonsPanel(String[] labels,
String[] names, Map<String, JButton> controls) {
JPanel panel = new JPanel();
panel.invalidate();
panel.setVisible(true);
JPanel buttonsPanel = GuiUtils.ComponentCreator.newPanel();
buttonsPanel.setLayout(new GridLayout(1, labels.length, 10, 10));
panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
for (int i = 0; i < labels.length; i++) {
JButton next = GuiUtils.ComponentCreator.newButton(labels[i]);
controls.put(names[i], next);
buttonsPanel.add(next);
}
panel.add(buttonsPanel);
return wrapComponentInBorderLayout(panel, BorderLayout.SOUTH);
}
public static JPanel createLeftAlignedButtonsPanel(String[] labels,
String[] names, Map<String, JButton> controls) {
JPanel panel = new JPanel();
panel.invalidate();
panel.setVisible(true);
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
JPanel buttonsPanel = GuiUtils.ComponentCreator.newPanel();
buttonsPanel.setLayout(new GridLayout(1, labels.length, 10, 10));
for (int i = 0; i < labels.length; i++) {
JButton next = GuiUtils.ComponentCreator.newButton(labels[i]);
controls.put(names[i], next);
buttonsPanel.add(next);
}
panel.add(buttonsPanel);
return wrapComponentInBorderLayout(panel, BorderLayout.SOUTH);
}
}
public static void setComponentWidth(JComponent component, int width) {
component.setPreferredSize(new Dimension(width, component
.getPreferredSize().height));
component.setMaximumSize(new Dimension(width, component
.getMaximumSize().height));
component.setMinimumSize(new Dimension(width, component
.getMinimumSize().height));
}
public static void setComponentHeight(JComponent component, int height) {
component.setPreferredSize(new Dimension(
component.getPreferredSize().width, height));
component.setMinimumSize(new Dimension(
component.getMinimumSize().width, height));
component.setMaximumSize(new Dimension(
component.getMaximumSize().width, height));
}
public static final int getDefaultFontHeight(final JComponent component) {
FontMetrics fontMetrics = component.getFontMetrics(component.getFont());
return (fontMetrics.getAscent() + fontMetrics.getDescent());
}
public static JScrollPane wrapScroller(JComponent comp, int... dims) {
JScrollPane sp = new JScrollPane();
sp.setBorder(new LineBorder(Color.LIGHT_GRAY, 0));
sp.setViewportView(comp);
if (dims != null && dims.length == 2) {
Dimension givenDimension = new Dimension(dims[0], dims[1]);
sp.setMinimumSize(givenDimension);
sp.setMaximumSize(givenDimension);
sp.setPreferredSize(givenDimension);
}
sp.setVisible(true);
sp.invalidate();
return sp;
}
public static JComponent wrapCaption(JComponent comp, String caption) {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JLabel captionLabel = new JLabel(caption, null, SwingConstants.LEFT);
captionLabel.setBorder(new EtchedBorder());
captionLabel.invalidate();
captionLabel.setVisible(true);
panel.add(captionLabel, BorderLayout.NORTH);
panel.add(comp);
panel.invalidate();
panel.setVisible(true);
return panel;
}
}