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