package edu.princeton.toy.choosers; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; import edu.princeton.swing.*; /** * TColorChooserPane manages a set of colors for various indices and allows the user to change the * colors for those indices. It also offers a disabled option which generally tells the index not * to use that color (how that is done will be implementation dependant). * * @author btsang * @version 7.1 */ public class TColorChooserPane extends JPanel implements ActionListener, ListSelectionListener { private static final String CLASS_STRING = TColorChooserPane.class.toString(); /** * The command that causes the TColorChooserPane to update its components with the internal * data. */ public static final String UPDATE_COMMAND = CLASS_STRING + "#updateCommand"; /** * The command that causes the TColorChooserPane to open a color chooser dialog. */ public static final String CHANGE_COMMAND = CLASS_STRING + "#changeCommand"; private static final Border BLACK_BORDER = LineBorder.createBlackLineBorder(); private static final Border ETCHED_BORDER = new EtchedBorder(); private PList colorList; private JLabel previewLabel; private JPanel previewPanel; private JButton changeButton; private JCheckBox disabledCheckbox; private Color colors[]; private boolean disabled[]; private String colorNames[]; private String disabledDescriptions[]; /** * Creates a new TColorChooserPane. */ public TColorChooserPane(String colorNames[], String disabledDescriptions[]) { super(new GridBagLayout()); int length = colorNames.length; if (length != disabledDescriptions.length) throw new IllegalArgumentException(); this.colorNames = new String[length]; this.disabledDescriptions = new String[length]; this.colors = new Color[length]; this.disabled = new boolean[length]; for (int ctr = 0; ctr < length; ctr++) { this.colorNames[ctr] = colorNames[ctr]; this.disabledDescriptions[ctr] = disabledDescriptions[ctr]; } { // Prepare the inner panel JPanel innerPanel = new JPanel(new GridBagLayout()); innerPanel.setBorder(ETCHED_BORDER); { // Prepare the color list colorList = new PList(this.colorNames); colorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); colorList.setSelectedIndex(0); colorList.addListSelectionListener(this); JScrollPane scrollPane = new JScrollPane( colorList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED ); Dimension preferredSize = scrollPane.getPreferredSize(); preferredSize.width = 150; scrollPane.setPreferredSize(preferredSize); innerPanel.add( scrollPane, new GridBagConstraints( 0, 0, 1, 4, 0.0, 2.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(2, 2, 2, 2), 0, 0 ) ); } { // Prepare the preview label previewLabel = new JLabel("Current color"); innerPanel.add( previewLabel, new GridBagConstraints( 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); } { // Prepare the preview panel previewPanel = new JPanel(); previewPanel.setPreferredSize(new Dimension(100, 100)); innerPanel.add( previewPanel, new GridBagConstraints( 1, 1, 1, 1, 1.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); } { // Prepare the change button changeButton = new JButton("Change..."); changeButton.setActionCommand(CHANGE_COMMAND); changeButton.addActionListener(this); innerPanel.add( changeButton, new GridBagConstraints( 1, 2, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); } { // Prepare the disabled checkbox disabledCheckbox = new JCheckBox(); disabledCheckbox.setActionCommand(UPDATE_COMMAND); disabledCheckbox.addActionListener(this); innerPanel.add( disabledCheckbox, new GridBagConstraints( 1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); } add( innerPanel, new GridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(50, 25, 50, 25), 0, 0 ) ); } doCommand(UPDATE_COMMAND, null); } /** * Gets the color for a given index. * * @param index The index of the requested color. An invalid value will result in an * ArrayIndexOutOfBoundsException. * @return The color for that index. */ public Color getColor(int index) { return colors[index]; } /** * Sets the color for a given index. * * @param color The new color for the given index. A null value will result in a * NullPointerException. * @param index The index of the color we're setting. An invalid value will result in an * ArrayIndexOutOfBoundsException. */ public void setColor(Color color, int index) { if (color == null) throw new NullPointerException(); colors[index] = color; if (colorList.getSelectedIndex() == index) { doCommand(UPDATE_COMMAND, null); } } /** * Returns wheter or not the color for a given index should be used. The behavior of the * objects to which the disabled index correspond is up to the user. * * @param index The index of the requested disabled state. An invalid value will result in an * ArrayIndexOutOfBoundsException. * @return The disabled state for that index. */ public boolean isDisabled(int index) { return disabled[index]; } /** * Sets the disabled state for a given index. The behavior of the objects to which the * disabled index correspond is up to the user. * * @param disabled The new disabled state for the given index. * @param index The index of the disabled state we're setting. An invalid value will result in * an ArrayIndexOutOfBoundsException. */ public void setDisabled(boolean disabled, int index) { this.disabled[index] = disabled; if (colorList.getSelectedIndex() == index) { doCommand(UPDATE_COMMAND, null); } } /** * Performs a command based on the argument. * * @param command A string representing the command. Note that pointer equality (not string * equality) is tested here, so it is important to use the string constants defined in this * class. An IllegalArgumentException will be thrown if the argument is invalid. * @return True iff the command was executed sucessfully. */ public synchronized boolean doCommand(String command, Object extraInfo) { //////////////////////////////////////////////////////////////////////////////////////////// if (command == UPDATE_COMMAND) { int index = colorList.getSelectedIndex(); if (index == -1) { index = 0; colorList.setSelectedIndex(0); } disabledCheckbox.setText(disabledDescriptions[index]); if (disabled[index]) { previewLabel.setEnabled(false); previewPanel.setBorder(ETCHED_BORDER); previewPanel.setBackground(null); changeButton.setEnabled(false); disabledCheckbox.getModel().setSelected(true); } else { previewLabel.setEnabled(true); previewPanel.setBorder(BLACK_BORDER); previewPanel.setBackground(colors[index]); changeButton.setEnabled(true); disabledCheckbox.getModel().setSelected(false); } return true; } //////////////////////////////////////////////////////////////////////////////////////////// if (command == CHANGE_COMMAND) { int index = colorList.getSelectedIndex(); if (index == -1) { index = 0; colorList.setSelectedIndex(0); } Component comp = this; while (comp != null && !(comp instanceof Window)) comp = comp.getParent(); Color selection = JColorChooser.showDialog( comp, "Color selection for " + colorNames[index], colors[index] ); if (selection != null) colors[index] = selection; doCommand(UPDATE_COMMAND, null); return true; } throw new IllegalArgumentException(); } /** * Implement ActionListener to pay attention to changes in the disabledCheckbox and * changeButton. */ public void actionPerformed(ActionEvent e) { int index = colorList.getSelectedIndex(); if (index != -1) disabled[index] = disabledCheckbox.getModel().isSelected(); doCommand(e.getActionCommand(), null); } /** * Implement ListSelectionListener to pay attention to changes in the colorList. */ public void valueChanged(ListSelectionEvent e) { doCommand(UPDATE_COMMAND, null); } }