1. /*
  2. * @(#)JColorChooser.java 1.30 00/04/06
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import java.beans.*;
  14. import java.io.*;
  15. import java.util.*;
  16. import javax.swing.colorchooser.*;
  17. import javax.swing.plaf.ColorChooserUI;
  18. import javax.swing.event.*;
  19. import javax.accessibility.*;
  20. /**
  21. * <code>JColorChooser</code> provides a pane of controls designed to allow
  22. * a user to manipulate and select a color.
  23. * For information about using color choosers, see
  24. * <a
  25. href="http://java.sun.com/docs/books/tutorial/uiswing/components/colorchooser.html">How to Use Color Choosers</a>,
  26. * a section in <em>The Java Tutorial</em>.
  27. *
  28. * <p>
  29. *
  30. * This class provides three levels of API:
  31. * <ol>
  32. * <li>A static convenience method which shows a modal color-chooser
  33. * dialog and returns the color selected by the user.
  34. * <li>A static convenience method for creating a color-chooser dialog
  35. * where <code>ActionListeners</code> can be specified to be invoked when
  36. * the user presses one of the dialog buttons.
  37. * <li>The ability to create instances of <code>JColorChooser</code> panes
  38. * directly (within any container). <code>PropertyChange</code> listeners
  39. * can be added to detect when the current "color" property changes.
  40. * </ol>
  41. * <p>
  42. * <strong>Warning:</strong>
  43. * Serialized objects of this class will not be compatible with
  44. * future Swing releases. The current serialization support is appropriate
  45. * for short term storage or RMI between applications running the same
  46. * version of Swing. A future release of Swing will provide support for
  47. * long term persistence.
  48. *
  49. *
  50. * @beaninfo
  51. * attribute: isContainer false
  52. * description: A component that supports selecting a Color.
  53. *
  54. *
  55. * @version 1.30 04/06/00
  56. * @author James Gosling
  57. * @author Amy Fowler
  58. * @author Steve Wilson
  59. */
  60. public class JColorChooser extends JComponent implements Accessible {
  61. /**
  62. * @see #getUIClassID
  63. * @see #readObject
  64. */
  65. private static final String uiClassID = "ColorChooserUI";
  66. private ColorSelectionModel selectionModel;
  67. private JComponent previewPanel;
  68. private AbstractColorChooserPanel[] chooserPanels = new AbstractColorChooserPanel[0];
  69. /**
  70. * The selection model property name.
  71. */
  72. public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
  73. /**
  74. * The preview panel property name.
  75. */
  76. public static final String PREVIEW_PANEL_PROPERTY = "previewPanel";
  77. /**
  78. * The chooserPanel array property name.
  79. */
  80. public static final String CHOOSER_PANELS_PROPERTY = "chooserPanels";
  81. /**
  82. * Shows a modal color-chooser dialog and blocks until the
  83. * dialog is hidden. If the user presses the "OK" button, then
  84. * this method hides/disposes the dialog and returns the selected color.
  85. * If the user presses the "Cancel" button or closes the dialog without
  86. * pressing "OK", then this method hides/disposes the dialog and returns
  87. * <code>null</code>.
  88. *
  89. * @param component the parent <code>Component</code> for the dialog
  90. * @param title the String containing the dialog's title
  91. * @param initialColor the initial Color set when the color-chooser is shown
  92. */
  93. public static Color showDialog(Component component,
  94. String title, Color initialColor) {
  95. final JColorChooser pane = new JColorChooser(initialColor != null?
  96. initialColor : Color.white);
  97. ColorTracker ok = new ColorTracker(pane);
  98. JDialog dialog = createDialog(component, title, true, pane, ok, null);
  99. dialog.addWindowListener(new ColorChooserDialog.Closer());
  100. dialog.addComponentListener(new ColorChooserDialog.DisposeOnClose());
  101. dialog.show(); // blocks until user brings dialog down...
  102. return ok.getColor();
  103. }
  104. /**
  105. * Creates and returns a new dialog containing the specified
  106. * <code>ColorChooser</code>` pane along with "OK", "Cancel", and "Reset"
  107. * buttons. If the "OK" or "Cancel" buttons are pressed, the dialog is
  108. * automatically hidden (but not disposed). If the "Reset"
  109. * button is pressed, the color-chooser's color will be reset to the
  110. * color which was set the last time <code>show</code> was invoked on the
  111. * dialog and the dialog will remain showing.
  112. *
  113. * @param c the parent component for the dialog
  114. * @param title the title for the dialog
  115. * @param modal a boolean. When true, the remainder of the program
  116. * is inactive until the dialog is closed.
  117. * @param chooserPane the color-chooser to be placed inside the dialog
  118. * @param okListener the ActionListener invoked when "OK" is pressed
  119. * @param cancelListener the ActionListener invoked when "Cancel" is pressed
  120. */
  121. public static JDialog createDialog(Component c, String title, boolean modal,
  122. JColorChooser chooserPane,
  123. ActionListener okListener,
  124. ActionListener cancelListener) {
  125. return new ColorChooserDialog(c, title, modal, chooserPane,
  126. okListener, cancelListener);
  127. }
  128. /**
  129. * Creates a color chooser pane with an initial color of white.
  130. */
  131. public JColorChooser() {
  132. this(Color.white);
  133. }
  134. /**
  135. * Creates a color chooser pane with the specified initial color.
  136. *
  137. * @param initialColor the initial color set in the chooser
  138. */
  139. public JColorChooser(Color initialColor) {
  140. this( new DefaultColorSelectionModel(initialColor) );
  141. }
  142. /**
  143. * Creates a color chooser pane with the specified
  144. * <code>ColorSelectionModel</code>.
  145. *
  146. * @param initialColor the initial color set in the chooser
  147. */
  148. public JColorChooser(ColorSelectionModel model) {
  149. selectionModel = model;
  150. updateUI();
  151. }
  152. /**
  153. * Returns the L&F object that renders this component.
  154. *
  155. * @return the ColorChooserUI object that renders this component
  156. */
  157. public ColorChooserUI getUI() {
  158. return (ColorChooserUI)ui;
  159. }
  160. /**
  161. * Sets the L&F object that renders this component.
  162. *
  163. * @param ui the ColorChooserUI L&F object
  164. * @see UIDefaults#getUI
  165. *
  166. * @beaninfo
  167. * bound: true
  168. * hidden: true
  169. * description: The UI object that implements the color chooser's LookAndFeel.
  170. */
  171. public void setUI(ColorChooserUI ui) {
  172. super.setUI(ui);
  173. }
  174. /**
  175. * Notification from the <code>UIManager</code> that the L&F has changed.
  176. * Replaces the current UI object with the latest version from the
  177. * <code>UIManager</code>.
  178. *
  179. * @see JComponent#updateUI
  180. */
  181. public void updateUI() {
  182. setUI((ColorChooserUI)UIManager.getUI(this));
  183. }
  184. /**
  185. * Returns the name of the L&F class that renders this component.
  186. *
  187. * @return the string "ColorChooserUI"
  188. * @see JComponent#getUIClassID
  189. * @see UIDefaults#getUI
  190. */
  191. public String getUIClassID() {
  192. return uiClassID;
  193. }
  194. /**
  195. * Gets the current color value from the color chooser.
  196. * By default, this delegates to the model.
  197. *
  198. * @return the current color value of the color chooser
  199. */
  200. public Color getColor() {
  201. return selectionModel.getSelectedColor();
  202. }
  203. /**
  204. * Sets the current color of the color chooser to the
  205. * specified color.
  206. * This will fire a <code>PropertyChangeEvent</code> for the property
  207. * named "color".
  208. *
  209. * @param color the color to be set in the color chooser
  210. * @see JComponent#addPropertyChangeListener
  211. *
  212. * @beaninfo
  213. * bound: false
  214. * hidden: false
  215. * description: The current color the chooser is to display.
  216. */
  217. public void setColor(Color color) {
  218. selectionModel.setSelectedColor(color);
  219. }
  220. /**
  221. * Sets the current color of the color chooser to the
  222. * specified RGB color. Note that the values of red, green,
  223. * and blue should be between the numbers 0 and 255, inclusive.
  224. *
  225. * @param r an int specifying the amount of Red
  226. * @param g an int specifying the amount of Green
  227. * @param b an int specifying the amount of Blue
  228. * @exception IllegalArgumentException if r,g,b values are out of range
  229. * @see java.awt.Color
  230. */
  231. public void setColor(int r, int g, int b) {
  232. setColor(new Color(r,g,b));
  233. }
  234. /**
  235. * Sets the current color of the color chooser to the
  236. * specified color.
  237. *
  238. * @param c an int value that sets the current color in the chooser
  239. * where the low-order 8 bits specify the Blue value,
  240. * the next 8 bits specify the Green value, and the 8 bits
  241. * above that specify the Red value.
  242. */
  243. public void setColor(int c) {
  244. setColor((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);
  245. }
  246. /**
  247. * Sets the current preview panel.
  248. * This will fire a <code>PropertyChangeEvent</code> for the property
  249. * named "previewPanel".
  250. *
  251. * @param color the color to be set in the color chooser
  252. * @see JComponent#addPropertyChangeListener
  253. *
  254. * @beaninfo
  255. * bound: true
  256. * hidden: true
  257. * description: The UI component which displays the current color.
  258. */
  259. public void setPreviewPanel(JComponent preview) {
  260. if (previewPanel != preview) {
  261. JComponent oldPreview = previewPanel;
  262. previewPanel = preview;
  263. firePropertyChange(JColorChooser.PREVIEW_PANEL_PROPERTY, oldPreview, preview);
  264. }
  265. }
  266. /**
  267. * Returns the preview panel that shows a chosen color.
  268. *
  269. * @return a JComponent object -- the preview panel
  270. */
  271. public JComponent getPreviewPanel() {
  272. return previewPanel;
  273. }
  274. /**
  275. * Adds a color chooser panel to the color chooser.
  276. *
  277. */
  278. public void addChooserPanel( AbstractColorChooserPanel panel ) {
  279. AbstractColorChooserPanel[] oldPanels = getChooserPanels();
  280. AbstractColorChooserPanel[] newPanels = new AbstractColorChooserPanel[oldPanels.length+1];
  281. System.arraycopy(oldPanels, 0, newPanels, 0, oldPanels.length);
  282. newPanels[newPanels.length-1] = panel;
  283. setChooserPanels(newPanels);
  284. }
  285. /**
  286. * Removes the Color Panel specified.
  287. *
  288. * @exception IllegalArgumentException if panel is not in list of
  289. * known chooser panels
  290. * @param name a string that specifies the panel to be removed
  291. * @return the color panel
  292. */
  293. public AbstractColorChooserPanel removeChooserPanel( AbstractColorChooserPanel panel ) {
  294. int containedAt = -1;
  295. for (int i = 0; i < chooserPanels.length; i++) {
  296. if (chooserPanels[i] == panel) {
  297. containedAt = i;
  298. break;
  299. }
  300. }
  301. if (containedAt == -1) {
  302. throw new IllegalArgumentException("chooser panel not in this chooser");
  303. }
  304. AbstractColorChooserPanel[] newArray = new AbstractColorChooserPanel[chooserPanels.length-1];
  305. if (containedAt == chooserPanels.length-1) { // at end
  306. System.arraycopy(chooserPanels, 0, newArray, 0, newArray.length);
  307. }
  308. else if (containedAt == 0) { // at start
  309. System.arraycopy(chooserPanels, 1, newArray, 0, newArray.length);
  310. }
  311. else { // in middle
  312. System.arraycopy(chooserPanels, 0, newArray, 0, containedAt);
  313. System.arraycopy(chooserPanels, containedAt+1,
  314. newArray, containedAt, (chooserPanels.length - containedAt - 1));
  315. }
  316. setChooserPanels(newArray);
  317. return panel;
  318. }
  319. /**
  320. * Specifies the Color Panels used to choose a color value.
  321. *
  322. * @param panels an array of AbstractColorChooserPanel object
  323. *
  324. * @beaninfo
  325. * bound: true
  326. * hidden: true
  327. * description: An array of different chooser types.
  328. */
  329. public void setChooserPanels( AbstractColorChooserPanel[] panels) {
  330. AbstractColorChooserPanel[] oldValue = chooserPanels;
  331. chooserPanels = panels;
  332. firePropertyChange(CHOOSER_PANELS_PROPERTY, oldValue, panels);
  333. }
  334. /**
  335. * Returns the specified color panels.
  336. *
  337. * @return an array of AbstractColorChooserPanel objects
  338. */
  339. public AbstractColorChooserPanel[] getChooserPanels() {
  340. return chooserPanels;
  341. }
  342. /**
  343. * Returns the data model that handles color selections.
  344. *
  345. * @return a ColorSelectionModel object
  346. */
  347. public ColorSelectionModel getSelectionModel() {
  348. return selectionModel;
  349. }
  350. /**
  351. * Set the model containing the selected color.
  352. *
  353. * @param newModel the new ColorSelectionModel object
  354. *
  355. * @beaninfo
  356. * bound: true
  357. * hidden: true
  358. * description: The model which contains the currently selected color.
  359. */
  360. public void setSelectionModel(ColorSelectionModel newModel ) {
  361. ColorSelectionModel oldModel = selectionModel;
  362. selectionModel = newModel;
  363. firePropertyChange(JColorChooser.SELECTION_MODEL_PROPERTY, oldModel, newModel);
  364. }
  365. /**
  366. * See <code>readObject</code> and <code>writeObject</code> in
  367. * <code>JComponent</code> for more
  368. * information about serialization in Swing.
  369. */
  370. private void writeObject(ObjectOutputStream s) throws IOException {
  371. s.defaultWriteObject();
  372. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  373. ui.installUI(this);
  374. }
  375. }
  376. /**
  377. * Returns a string representation of this <code>JColorChooser</code>.
  378. * This method
  379. * is intended to be used only for debugging purposes, and the
  380. * content and format of the returned string may vary between
  381. * implementations. The returned string may be empty but may not
  382. * be <code>null</code>.
  383. *
  384. * @return a string representation of this <code>JColorChooser</code>
  385. */
  386. protected String paramString() {
  387. StringBuffer chooserPanelsString = new StringBuffer("");
  388. for (int i=0; i<chooserPanels.length; i++) {
  389. chooserPanelsString.append("[" + chooserPanels[i].toString()
  390. + "]");
  391. }
  392. String previewPanelString = (previewPanel != null ?
  393. previewPanel.toString() : "");
  394. return super.paramString() +
  395. ",chooserPanels=" + chooserPanelsString.toString() +
  396. ",previewPanel=" + previewPanelString;
  397. }
  398. /////////////////
  399. // Accessibility support
  400. ////////////////
  401. protected AccessibleContext accessibleContext = null;
  402. /**
  403. * Gets the AccessibleContext associated with this JColorChooser.
  404. * For color choosers, the AccessibleContext takes the form of an
  405. * AccessibleJColorChooser.
  406. * A new AccessibleJColorChooser instance is created if necessary.
  407. *
  408. * @return an AccessibleJColorChooser that serves as the
  409. * AccessibleContext of this JColorChooser
  410. */
  411. public AccessibleContext getAccessibleContext() {
  412. if (accessibleContext == null) {
  413. accessibleContext = new AccessibleJColorChooser();
  414. }
  415. return accessibleContext;
  416. }
  417. /**
  418. * This class implements accessibility support for the
  419. * <code>JColorChooser</code> class. It provides an implementation of the
  420. * Java Accessibility API appropriate to color chooser user-interface
  421. * elements.
  422. */
  423. protected class AccessibleJColorChooser extends AccessibleJComponent {
  424. /**
  425. * Get the role of this object.
  426. *
  427. * @return an instance of AccessibleRole describing the role of the
  428. * object
  429. * @see AccessibleRole
  430. */
  431. public AccessibleRole getAccessibleRole() {
  432. return AccessibleRole.COLOR_CHOOSER;
  433. }
  434. } // inner class AccessibleJColorChooser
  435. }
  436. /*
  437. * Class which builds a color chooser dialog consisting of
  438. * a JColorChooser with "Ok", "Cancel", and "Reset" buttons.
  439. *
  440. * Note: This needs to be fixed to deal with localization!
  441. */
  442. class ColorChooserDialog extends JDialog {
  443. private Color initialColor;
  444. private JColorChooser chooserPane;
  445. public ColorChooserDialog(Component c, String title, boolean modal,
  446. JColorChooser chooserPane,
  447. ActionListener okListener, ActionListener cancelListener) {
  448. super(JOptionPane.getFrameForComponent(c), title, modal);
  449. //setResizable(false);
  450. this.chooserPane = chooserPane;
  451. String okString = UIManager.getString("ColorChooser.okText");
  452. String cancelString = UIManager.getString("ColorChooser.cancelText");
  453. String resetString = UIManager.getString("ColorChooser.resetText");
  454. Container contentPane = getContentPane();
  455. contentPane.setLayout(new BorderLayout());
  456. contentPane.add(chooserPane, BorderLayout.CENTER);
  457. /*
  458. * Create Lower button panel
  459. */
  460. JPanel buttonPane = new JPanel();
  461. buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER));
  462. JButton okButton = new JButton(okString);
  463. getRootPane().setDefaultButton(okButton);
  464. okButton.setActionCommand("OK");
  465. if (okListener != null) {
  466. okButton.addActionListener(okListener);
  467. }
  468. okButton.addActionListener(new ActionListener() {
  469. public void actionPerformed(ActionEvent e) {
  470. hide();
  471. }
  472. });
  473. buttonPane.add(okButton);
  474. JButton cancelButton = new JButton(cancelString);
  475. // The following few lines are used to register esc to close the dialog
  476. Action cancelKeyAction = new AbstractAction() {
  477. public void actionPerformed(ActionEvent e) {
  478. ((AbstractButton)e.getSource()).fireActionPerformed(e);
  479. }
  480. };
  481. KeyStroke cancelKeyStroke = KeyStroke.getKeyStroke((char)KeyEvent.VK_ESCAPE, false);
  482. InputMap inputMap = cancelButton.getInputMap(JComponent.
  483. WHEN_IN_FOCUSED_WINDOW);
  484. ActionMap actionMap = cancelButton.getActionMap();
  485. if (inputMap != null && actionMap != null) {
  486. inputMap.put(cancelKeyStroke, "cancel");
  487. actionMap.put("cancel", cancelKeyAction);
  488. }
  489. // end esc handling
  490. cancelButton.setActionCommand("cancel");
  491. if (cancelListener != null) {
  492. cancelButton.addActionListener(cancelListener);
  493. }
  494. cancelButton.addActionListener(new ActionListener() {
  495. public void actionPerformed(ActionEvent e) {
  496. hide();
  497. }
  498. });
  499. buttonPane.add(cancelButton);
  500. JButton resetButton = new JButton(resetString);
  501. resetButton.addActionListener(new ActionListener() {
  502. public void actionPerformed(ActionEvent e) {
  503. reset();
  504. }
  505. });
  506. buttonPane.add(resetButton);
  507. contentPane.add(buttonPane, BorderLayout.SOUTH);
  508. pack();
  509. setLocationRelativeTo(c);
  510. }
  511. public void show() {
  512. initialColor = chooserPane.getColor();
  513. super.show();
  514. }
  515. public void reset() {
  516. chooserPane.setColor(initialColor);
  517. }
  518. static class Closer extends WindowAdapter implements Serializable{
  519. public void windowClosing(WindowEvent e) {
  520. Window w = e.getWindow();
  521. w.hide();
  522. }
  523. }
  524. static class DisposeOnClose extends ComponentAdapter implements Serializable{
  525. public void componentHidden(ComponentEvent e) {
  526. Window w = (Window)e.getComponent();
  527. w.dispose();
  528. }
  529. }
  530. }
  531. class ColorTracker implements ActionListener, Serializable {
  532. JColorChooser chooser;
  533. Color color;
  534. public ColorTracker(JColorChooser c) {
  535. chooser = c;
  536. }
  537. public void actionPerformed(ActionEvent e) {
  538. color = chooser.getColor();
  539. }
  540. public Color getColor() {
  541. return color;
  542. }
  543. }