Source for javax.swing.JColorChooser

   1: /* JColorChooser.java --
   2:    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.AWTError;
  42: import java.awt.BorderLayout;
  43: import java.awt.Color;
  44: import java.awt.Component;
  45: import java.awt.Dialog;
  46: import java.awt.FlowLayout;
  47: import java.awt.Frame;
  48: import java.awt.event.ActionEvent;
  49: import java.awt.event.ActionListener;
  50: 
  51: import javax.accessibility.Accessible;
  52: import javax.accessibility.AccessibleContext;
  53: import javax.accessibility.AccessibleRole;
  54: import javax.swing.colorchooser.AbstractColorChooserPanel;
  55: import javax.swing.colorchooser.ColorSelectionModel;
  56: import javax.swing.colorchooser.DefaultColorSelectionModel;
  57: import javax.swing.plaf.ColorChooserUI;
  58: 
  59: 
  60: /**
  61:  * A Swing widget that offers users different ways to
  62:  * select a color. By default, three different panels are presented to the
  63:  * user that are capable of changing the selected color. There are three ways
  64:  * to utilize JColorChooser. The first is to build a JColorChooser and add it
  65:  * to the content pane. The second is to use the createDialog method to
  66:  * create a JDialog that holds a JColorChooser. The third is to show a
  67:  * JColorChooser in a JDialog directly using the showDialog method.
  68:  *
  69:  * @author original author unknown
  70:  */
  71: public class JColorChooser extends JComponent implements Accessible
  72: {
  73:   /** DOCUMENT ME! */
  74:   private static final long serialVersionUID = 9168066781620640889L;
  75: 
  76:   /**
  77:    * Accessibility support for <code>JColorChooser</code>.
  78:    */
  79:   protected class AccessibleJColorChooser
  80:     extends JComponent.AccessibleJComponent
  81:   {
  82:     /** DOCUMENT ME! */
  83:     private static final long serialVersionUID = -2038297864782299082L;
  84: 
  85:     /**
  86:      * Constructor AccessibleJColorChooser
  87:      */
  88:     protected AccessibleJColorChooser()
  89:     {
  90:       // Nothing to do here.
  91:     }
  92: 
  93:     /**
  94:      * getAccessibleRole
  95:      *
  96:      * @return AccessibleRole
  97:      */
  98:     public AccessibleRole getAccessibleRole()
  99:     {
 100:       return AccessibleRole.COLOR_CHOOSER;
 101:     } // getAccessibleRole()
 102:   } // AccessibleJColorChooser
 103: 
 104:   /** The model used with the JColorChooser. */
 105:   private ColorSelectionModel selectionModel;
 106: 
 107:   /** The preview panel associated with the JColorChooser. */
 108:   private JComponent previewPanel;
 109: 
 110:   /**
 111:    * The set of AbstractColorChooserPanels associated with the JColorChooser.
 112:    */
 113:   private AbstractColorChooserPanel[] chooserPanels;
 114: 
 115:   /** A Drag and Drop property. */
 116:   private boolean dragEnabled;
 117: 
 118:   /**
 119:    * The property fired by the JColorChooser when the selectionModel property
 120:    * changes.
 121:    */
 122:   public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
 123: 
 124:   /**
 125:    * The property fired by the JColorChooser when the previewPanel property
 126:    * changes.
 127:    */
 128:   public static final String PREVIEW_PANEL_PROPERTY = "previewPanel";
 129: 
 130:   /**
 131:    * The property fired by the JColorChooser when the chooserPanels property
 132:    * changes.
 133:    */
 134:   public static final String CHOOSER_PANELS_PROPERTY = "chooserPanels";
 135: 
 136:   /** accessibleContext */
 137:   protected AccessibleContext accessibleContext;
 138: 
 139:   /**
 140:    * This method creates a new JColorChooser with the default initial color.
 141:    */
 142:   public JColorChooser()
 143:   {
 144:     this(new DefaultColorSelectionModel());
 145:   } // JColorChooser()
 146: 
 147:   /**
 148:    * This method creates a new JColorChooser with the given initial color.
 149:    *
 150:    * @param initial The initial color.
 151:    */
 152:   public JColorChooser(Color initial)
 153:   {
 154:     this(new DefaultColorSelectionModel(initial));
 155:   } // JColorChooser()
 156: 
 157:   /**
 158:    * This method creates a new JColorChooser with the given model. The model
 159:    * will dictate what the initial color for the JColorChooser is.
 160:    *
 161:    * @param model The Model to use with the JColorChooser.
 162:    */
 163:   public JColorChooser(ColorSelectionModel model)
 164:   {
 165:     if (model == null)
 166:       model = new DefaultColorSelectionModel();
 167:     selectionModel = model;
 168:     updateUI();
 169:   } // JColorChooser()
 170: 
 171:   /**
 172:    * This method sets the current color for the JColorChooser.
 173:    *
 174:    * @param color The new color for the JColorChooser.
 175:    */
 176:   public void setColor(Color color)
 177:   {
 178:     if (color != null)
 179:       selectionModel.setSelectedColor(color);
 180:   } // setColor()
 181: 
 182:   /**
 183:    * This method sets the current color for the JColorChooser using RGB
 184:    * values.
 185:    *
 186:    * @param r The red value.
 187:    * @param g The green value.
 188:    * @param b The blue value.
 189:    */
 190:   public void setColor(int r, int g, int b)
 191:   {
 192:     selectionModel.setSelectedColor(new Color(r, g, b));
 193:   } // setColor()
 194: 
 195:   /**
 196:    * This method sets the current color for the JColorChooser using the
 197:    * integer value. Bits 0-7 represent the blue value. Bits 8-15 represent
 198:    * the green value. Bits 16-23 represent the red value.
 199:    *
 200:    * @param color The new current color of the JColorChooser.
 201:    */
 202:   public void setColor(int color)
 203:   {
 204:     setColor(new Color(color, false));
 205:   } // setColor()
 206: 
 207:   /**
 208:    * This method shows a JColorChooser inside a JDialog. The JDialog will
 209:    * block until it is hidden. The JDialog comes with three buttons: OK,
 210:    * Cancel, and Reset. Pressing OK or Cancel hide the JDialog. Pressing
 211:    * Reset will reset the JColorChooser to its initial value.
 212:    *
 213:    * @param component The Component that parents the JDialog.
 214:    * @param title The title displayed in the JDialog.
 215:    * @param initial The initial color.
 216:    *
 217:    * @return The selected color.
 218:    */
 219:   public static Color showDialog(Component component, String title,
 220:                                  Color initial)
 221:   {
 222:     JColorChooser choose = new JColorChooser(initial);
 223: 
 224:     JDialog dialog = createDialog(component, title, true, choose, null, null);
 225: 
 226:     dialog.getContentPane().add(choose);
 227:     dialog.pack();
 228:     dialog.show();
 229: 
 230:     return choose.getColor();
 231:   } // showDialog()
 232: 
 233:   /**
 234:    * This is a helper method to make the given JDialog block until it is
 235:    * hidden.  This is package-private to avoid an accessor method.
 236:    *
 237:    * @param dialog The JDialog to block.
 238:    */
 239:   static void makeModal(JDialog dialog)
 240:   {
 241:     try
 242:       {
 243:         synchronized (dialog)
 244:           {
 245:             while (dialog.isVisible())
 246:               dialog.wait();
 247:           }
 248:       }
 249:     catch (InterruptedException e)
 250:       {
 251:         // TODO: Should this be handled?
 252:       }
 253:   }
 254: 
 255:   /**
 256:    * This is a helper method to find the first Frame or Dialog ancestor of the
 257:    * given Component.
 258:    *
 259:    * @param c The Component to find ancestors for.
 260:    *
 261:    * @return A Frame or Dialog ancestor. Null if none are found.
 262:    */
 263:   private static Component findParent(Component c)
 264:   {
 265:     Component parent = SwingUtilities.getAncestorOfClass(Frame.class, c);
 266:     if (parent != null)
 267:       return parent;
 268:     parent = SwingUtilities.getAncestorOfClass(Dialog.class, c);
 269:     return parent;
 270:   }
 271: 
 272:   /**
 273:    * This method will take the given JColorChooser and place it in a JDialog
 274:    * with the given modal property. Three buttons are displayed in the
 275:    * JDialog: OK, Cancel and Reset. If OK or Cancel are pressed, the JDialog
 276:    * is hidden. If Reset is pressed, then the JColorChooser will take on its
 277:    * default color value. The given okListener will be registered to the OK
 278:    * button and the cancelListener will be registered to the Cancel button.
 279:    * If the modal property is set, then the JDialog will block until it is
 280:    * hidden.
 281:    *
 282:    * @param component The Component that will parent the JDialog.
 283:    * @param title The title displayed in the JDialog.
 284:    * @param modal The modal property.
 285:    * @param chooserPane The JColorChooser to place in the JDialog.
 286:    * @param okListener The ActionListener to register to the OK button.
 287:    * @param cancelListener The ActionListener to register to the Cancel
 288:    *        button.
 289:    *
 290:    * @return A JDialog with the JColorChooser inside of it.
 291:    *
 292:    * @throws AWTError If the component is not a suitable parent.
 293:    */
 294:   public static JDialog createDialog(Component component, String title,
 295:                                      boolean modal, JColorChooser chooserPane,
 296:                                      ActionListener okListener,
 297:                                      ActionListener cancelListener)
 298:   {
 299:     Component parent = findParent(component);
 300:     if (parent == null)
 301:       throw new AWTError("No suitable parent found for Component.");
 302:     JDialog dialog;
 303:     if (parent instanceof Frame)
 304:       dialog = new ModalDialog((Frame) parent, title);
 305:     else
 306:       dialog = new ModalDialog((Dialog) parent, title);
 307:     dialog.setModal(modal);
 308: 
 309:     dialog.getContentPane().setLayout(new BorderLayout());
 310: 
 311:     JPanel panel = new JPanel();
 312:     panel.setLayout(new FlowLayout());
 313: 
 314:     ActionListener al = new DefaultOKCancelListener(dialog);
 315: 
 316:     JButton ok = new JButton("OK");
 317:     ok.addActionListener(okListener);
 318:     ok.addActionListener(al);
 319: 
 320:     JButton cancel = new JButton("Cancel");
 321:     cancel.addActionListener(cancelListener);
 322:     cancel.addActionListener(al);
 323: 
 324:     JButton reset = new JButton("Reset");
 325:     reset.addActionListener(new DefaultResetListener(chooserPane));
 326: 
 327:     dialog.getContentPane().add(chooserPane, BorderLayout.NORTH);
 328: 
 329:     panel.add(ok);
 330:     panel.add(cancel);
 331:     panel.add(reset);
 332: 
 333:     dialog.getContentPane().add(panel, BorderLayout.SOUTH);
 334: 
 335:     return dialog;
 336:   } // createDialog()
 337: 
 338:   /**
 339:    * This method returns the UI Component used for this JColorChooser.
 340:    *
 341:    * @return The UI Component for this JColorChooser.
 342:    */
 343:   public ColorChooserUI getUI()
 344:   {
 345:     return (ColorChooserUI) ui;
 346:   } // getUI()
 347: 
 348:   /**
 349:    * This method sets the UI Component used for this JColorChooser.
 350:    *
 351:    * @param ui The UI Component to use with this JColorChooser.
 352:    */
 353:   public void setUI(ColorChooserUI ui)
 354:   {
 355:     super.setUI(ui);
 356:   } // setUI()
 357: 
 358:   /**
 359:    * This method resets the UI Component property to the Look and Feel
 360:    * default.
 361:    */
 362:   public void updateUI()
 363:   {
 364:     setUI((ColorChooserUI) UIManager.getUI(this));
 365:     revalidate();
 366:   } // updateUI()
 367: 
 368:   /**
 369:    * This method returns a String identifier for the UI Class to be used with
 370:    * the JColorChooser.
 371:    *
 372:    * @return The String identifier for the UI Class.
 373:    */
 374:   public String getUIClassID()
 375:   {
 376:     return "ColorChooserUI";
 377:   } // getUIClassID()
 378: 
 379:   /**
 380:    * This method returns the current color for the JColorChooser.
 381:    *
 382:    * @return The current color for the JColorChooser.
 383:    */
 384:   public Color getColor()
 385:   {
 386:     return selectionModel.getSelectedColor(); // TODO
 387:   } // getColor()
 388: 
 389:   /**
 390:    * This method changes the previewPanel property for the JTabbedPane. The
 391:    * previewPanel is responsible for indicating the current color of the
 392:    * JColorChooser.
 393:    *
 394:    * @param component The Component that will act as the previewPanel.
 395:    */
 396:   public void setPreviewPanel(JComponent component)
 397:   {
 398:     if (component != previewPanel)
 399:       {
 400:         JComponent old = previewPanel;
 401:         previewPanel = component;
 402:         firePropertyChange(PREVIEW_PANEL_PROPERTY, old, previewPanel);
 403:       }
 404:   } // setPreviewPanel()
 405: 
 406:   /**
 407:    * This method returns the current previewPanel used with this
 408:    * JColorChooser.
 409:    *
 410:    * @return The current previewPanel.
 411:    */
 412:   public JComponent getPreviewPanel()
 413:   {
 414:     return previewPanel; // TODO
 415:   } // getPreviewPanel()
 416: 
 417:   /**
 418:    * This method adds the given AbstractColorChooserPanel to the list of the
 419:    * JColorChooser's chooserPanels.
 420:    *
 421:    * @param panel The AbstractColorChooserPanel to add.
 422:    */
 423:   public void addChooserPanel(AbstractColorChooserPanel panel)
 424:   {
 425:     if (panel == null)
 426:       return;
 427:     AbstractColorChooserPanel[] old = chooserPanels;
 428:     AbstractColorChooserPanel[] newPanels =
 429:       new AbstractColorChooserPanel[(old == null) ? 1 : old.length + 1];
 430:     if (old != null)
 431:       System.arraycopy(old, 0, newPanels, 0, old.length);
 432:     newPanels[newPanels.length - 1] = panel;
 433:     chooserPanels = newPanels;
 434:     panel.installChooserPanel(this);
 435:     firePropertyChange(CHOOSER_PANELS_PROPERTY, old, newPanels);
 436:   } // addChooserPanel()
 437: 
 438:   /**
 439:    * This method removes the given AbstractColorChooserPanel from the
 440:    * JColorChooser's list of chooserPanels.
 441:    *
 442:    * @param panel The AbstractColorChooserPanel to remove.
 443:    *
 444:    * @return The AbstractColorChooserPanel that was removed.
 445:    */
 446:   public AbstractColorChooserPanel removeChooserPanel(AbstractColorChooserPanel panel)
 447:   {
 448:     int index = -1;
 449:     for (int i = 0; i < chooserPanels.length; i++)
 450:       if (panel == chooserPanels[i])
 451:         {
 452:           index = i;
 453:           break;
 454:         }
 455: 
 456:     if (index == -1)
 457:       return null;
 458: 
 459:     AbstractColorChooserPanel[] old = chooserPanels;
 460:     if (chooserPanels.length == 1)
 461:       chooserPanels = null;
 462:     else
 463:       {
 464:         AbstractColorChooserPanel[] newPanels =
 465:           new AbstractColorChooserPanel[chooserPanels.length - 1];
 466:         System.arraycopy(chooserPanels, 0, newPanels, 0, index);
 467:         System.arraycopy(chooserPanels, index, newPanels, index - 1,
 468:                          chooserPanels.length - index);
 469:         chooserPanels = newPanels;
 470:       }
 471:     panel.uninstallChooserPanel(this);
 472:     firePropertyChange(CHOOSER_PANELS_PROPERTY, old, chooserPanels);
 473:     return panel;
 474:   }
 475: 
 476:   /**
 477:    * This method sets the chooserPanels property for this JColorChooser.
 478:    *
 479:    * @param panels The new set of AbstractColorChooserPanels to use.
 480:    */
 481:   public void setChooserPanels(AbstractColorChooserPanel[] panels)
 482:   {
 483:     if (panels != chooserPanels)
 484:       {
 485:         if (chooserPanels != null)
 486:           for (int i = 0; i < chooserPanels.length; i++)
 487:             if (chooserPanels[i] != null)
 488:               chooserPanels[i].uninstallChooserPanel(this);
 489: 
 490:         AbstractColorChooserPanel[] old = chooserPanels;
 491:         chooserPanels = panels;
 492: 
 493:         if (panels != null)
 494:           for (int i = 0; i < panels.length; i++)
 495:             if (panels[i] != null)
 496:               panels[i].installChooserPanel(this);
 497: 
 498:         firePropertyChange(CHOOSER_PANELS_PROPERTY, old, chooserPanels);
 499:       }
 500:   } // setChooserPanels()
 501: 
 502:   /**
 503:    * This method returns the AbstractColorChooserPanels used with this
 504:    * JColorChooser.
 505:    *
 506:    * @return The AbstractColorChooserPanels used with this JColorChooser.
 507:    */
 508:   public AbstractColorChooserPanel[] getChooserPanels()
 509:   {
 510:     return chooserPanels;
 511:   } // getChooserPanels()
 512: 
 513:   /**
 514:    * This method returns the ColorSelectionModel used with this JColorChooser.
 515:    *
 516:    * @return The ColorSelectionModel.
 517:    */
 518:   public ColorSelectionModel getSelectionModel()
 519:   {
 520:     return selectionModel;
 521:   } // getSelectionModel()
 522: 
 523:   /**
 524:    * This method sets the ColorSelectionModel to be used with this
 525:    * JColorChooser.
 526:    *
 527:    * @param model The ColorSelectionModel to be used with this JColorChooser.
 528:    *
 529:    * @throws AWTError If the given model is null.
 530:    */
 531:   public void setSelectionModel(ColorSelectionModel model)
 532:   {
 533:     if (model == null)
 534:       throw new AWTError("ColorSelectionModel is not allowed to be null.");
 535:     selectionModel = model;
 536:   } // setSelectionModel()
 537: 
 538:   /**
 539:    * DOCUMENT ME!
 540:    *
 541:    * @return DOCUMENT ME!
 542:    */
 543:   public boolean getDragEnabled()
 544:   {
 545:     return dragEnabled;
 546:   }
 547: 
 548:   /**
 549:    * DOCUMENT ME!
 550:    *
 551:    * @param b DOCUMENT ME!
 552:    */
 553:   public void setDragEnabled(boolean b)
 554:   {
 555:     dragEnabled = b;
 556:   }
 557: 
 558:   /**
 559:    * This method returns a String describing the JColorChooser.
 560:    *
 561:    * @return A String describing the JColorChooser.
 562:    */
 563:   protected String paramString()
 564:   {
 565:     return "JColorChooser";
 566:   } // paramString()
 567: 
 568:   /**
 569:    * getAccessibleContext
 570:    *
 571:    * @return AccessibleContext
 572:    */
 573:   public AccessibleContext getAccessibleContext()
 574:   {
 575:     if (accessibleContext == null)
 576:       accessibleContext = new AccessibleJColorChooser();
 577: 
 578:     return accessibleContext;
 579:   }
 580: 
 581:   /**
 582:    * A helper class that hides a JDialog when the action is performed.
 583:    */
 584:   static class DefaultOKCancelListener implements ActionListener
 585:   {
 586:     /** The JDialog to hide. */
 587:     private JDialog dialog;
 588: 
 589:     /**
 590:      * Creates a new DefaultOKCancelListener with the given JDialog to hide.
 591:      *
 592:      * @param dialog The JDialog to hide.
 593:      */
 594:     public DefaultOKCancelListener(JDialog dialog)
 595:     {
 596:       super();
 597:       this.dialog = dialog;
 598:     }
 599: 
 600:     /**
 601:      * This method hides the JDialog when called.
 602:      *
 603:      * @param e The ActionEvent.
 604:      */
 605:     public void actionPerformed(ActionEvent e)
 606:     {
 607:       dialog.hide();
 608:     }
 609:   }
 610: 
 611:   /**
 612:    * This method resets the JColorChooser color to the initial color when the
 613:    * action is performed.
 614:    */
 615:   static class DefaultResetListener implements ActionListener
 616:   {
 617:     /** The JColorChooser to reset. */
 618:     private JColorChooser chooser;
 619: 
 620:     /** The initial color. */
 621:     private Color init;
 622: 
 623:     /**
 624:      * Creates a new DefaultResetListener with the given JColorChooser.
 625:      *
 626:      * @param chooser The JColorChooser to reset.
 627:      */
 628:     public DefaultResetListener(JColorChooser chooser)
 629:     {
 630:       super();
 631:       this.chooser = chooser;
 632:       init = chooser.getColor();
 633:     }
 634: 
 635:     /**
 636:      * This method resets the JColorChooser to its initial color.
 637:      *
 638:      * @param e The ActionEvent.
 639:      */
 640:     public void actionPerformed(ActionEvent e)
 641:     {
 642:       chooser.setColor(init);
 643:     }
 644:   }
 645: 
 646:   /**
 647:    * This is a custom JDialog that will notify when it is hidden and the modal
 648:    * property is set.
 649:    */
 650:   static class ModalDialog extends JDialog
 651:   {
 652:     /** The modal property. */
 653:     private boolean modal;
 654: 
 655:     /**
 656:      * Creates a new ModalDialog object with the given parent and title.
 657:      *
 658:      * @param parent The parent of the JDialog.
 659:      * @param title The title of the JDialog.
 660:      */
 661:     public ModalDialog(Frame parent, String title)
 662:     {
 663:       super(parent, title);
 664:     }
 665: 
 666:     /**
 667:      * Creates a new ModalDialog object with the given parent and title.
 668:      *
 669:      * @param parent The parent of the JDialog.
 670:      * @param title The title of the JDialog.
 671:      */
 672:     public ModalDialog(Dialog parent, String title)
 673:     {
 674:       super(parent, title);
 675:     }
 676: 
 677:     /**
 678:      * This method sets the modal property.
 679:      *
 680:      * @param modal The modal property.
 681:      */
 682:     public void setModal(boolean modal)
 683:     {
 684:       this.modal = modal;
 685:     }
 686: 
 687:     /**
 688:      * This method shows the ModalDialog.
 689:      */
 690:     public void show()
 691:     {
 692:       super.show();
 693:       if (modal)
 694:     makeModal(this);
 695:     }
 696: 
 697:     /**
 698:      * This method hides the ModalDialog.
 699:      */
 700:     public synchronized void hide()
 701:     {
 702:       super.hide();
 703:       notifyAll();
 704:     }
 705:   }
 706: }