001    /* JColorChooser.java --
002       Copyright (C) 2002, 2004 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import java.awt.AWTError;
042    import java.awt.BorderLayout;
043    import java.awt.Color;
044    import java.awt.Component;
045    import java.awt.Dialog;
046    import java.awt.FlowLayout;
047    import java.awt.Frame;
048    import java.awt.event.ActionEvent;
049    import java.awt.event.ActionListener;
050    
051    import javax.accessibility.Accessible;
052    import javax.accessibility.AccessibleContext;
053    import javax.accessibility.AccessibleRole;
054    import javax.swing.colorchooser.AbstractColorChooserPanel;
055    import javax.swing.colorchooser.ColorSelectionModel;
056    import javax.swing.colorchooser.DefaultColorSelectionModel;
057    import javax.swing.plaf.ColorChooserUI;
058    
059    
060    /**
061     * A Swing widget that offers users different ways to
062     * select a color. By default, three different panels are presented to the
063     * user that are capable of changing the selected color. There are three ways
064     * to utilize JColorChooser. The first is to build a JColorChooser and add it
065     * to the content pane. The second is to use the createDialog method to
066     * create a JDialog that holds a JColorChooser. The third is to show a
067     * JColorChooser in a JDialog directly using the showDialog method.
068     *
069     * @author original author unknown
070     */
071    public class JColorChooser extends JComponent implements Accessible
072    {
073      /** DOCUMENT ME! */
074      private static final long serialVersionUID = 9168066781620640889L;
075    
076      /**
077       * Accessibility support for <code>JColorChooser</code>.
078       */
079      protected class AccessibleJColorChooser
080        extends JComponent.AccessibleJComponent
081      {
082        /** DOCUMENT ME! */
083        private static final long serialVersionUID = -2038297864782299082L;
084    
085        /**
086         * Constructor AccessibleJColorChooser
087         */
088        protected AccessibleJColorChooser()
089        {
090          // Nothing to do here.
091        }
092    
093        /**
094         * getAccessibleRole
095         *
096         * @return AccessibleRole
097         */
098        public AccessibleRole getAccessibleRole()
099        {
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 JDialog((Frame) parent, title, true);
305        else
306          dialog = new JDialog((Dialog) parent, title, true);
307    
308        dialog.getContentPane().setLayout(new BorderLayout());
309    
310        JPanel panel = new JPanel();
311        panel.setLayout(new FlowLayout());
312    
313        ActionListener al = new DefaultOKCancelListener(dialog);
314    
315        JButton ok = new JButton("OK");
316        ok.addActionListener(okListener);
317        ok.addActionListener(al);
318    
319        JButton cancel = new JButton("Cancel");
320        cancel.addActionListener(cancelListener);
321        cancel.addActionListener(al);
322    
323        JButton reset = new JButton("Reset");
324        reset.addActionListener(new DefaultResetListener(chooserPane));
325    
326        dialog.getContentPane().add(chooserPane, BorderLayout.NORTH);
327    
328        panel.add(ok);
329        panel.add(cancel);
330        panel.add(reset);
331    
332        dialog.getContentPane().add(panel, BorderLayout.SOUTH);
333    
334        return dialog;
335      } // createDialog()
336    
337      /**
338       * This method returns the UI Component used for this JColorChooser.
339       *
340       * @return The UI Component for this JColorChooser.
341       */
342      public ColorChooserUI getUI()
343      {
344        return (ColorChooserUI) ui;
345      } // getUI()
346    
347      /**
348       * This method sets the UI Component used for this JColorChooser.
349       *
350       * @param ui The UI Component to use with this JColorChooser.
351       */
352      public void setUI(ColorChooserUI ui)
353      {
354        super.setUI(ui);
355      } // setUI()
356    
357      /**
358       * This method resets the UI Component property to the Look and Feel
359       * default.
360       */
361      public void updateUI()
362      {
363        setUI((ColorChooserUI) UIManager.getUI(this));
364      }
365    
366      /**
367       * This method returns a String identifier for the UI Class to be used with
368       * the JColorChooser.
369       *
370       * @return The String identifier for the UI Class.
371       */
372      public String getUIClassID()
373      {
374        return "ColorChooserUI";
375      } // getUIClassID()
376    
377      /**
378       * This method returns the current color for the JColorChooser.
379       *
380       * @return The current color for the JColorChooser.
381       */
382      public Color getColor()
383      {
384        return selectionModel.getSelectedColor(); // TODO
385      } // getColor()
386    
387      /**
388       * This method changes the previewPanel property for the JTabbedPane. The
389       * previewPanel is responsible for indicating the current color of the
390       * JColorChooser.
391       *
392       * @param component The Component that will act as the previewPanel.
393       */
394      public void setPreviewPanel(JComponent component)
395      {
396        if (component != previewPanel)
397          {
398            JComponent old = previewPanel;
399            previewPanel = component;
400            firePropertyChange(PREVIEW_PANEL_PROPERTY, old, previewPanel);
401          }
402      } // setPreviewPanel()
403    
404      /**
405       * This method returns the current previewPanel used with this
406       * JColorChooser.
407       *
408       * @return The current previewPanel.
409       */
410      public JComponent getPreviewPanel()
411      {
412        return previewPanel; // TODO
413      } // getPreviewPanel()
414    
415      /**
416       * This method adds the given AbstractColorChooserPanel to the list of the
417       * JColorChooser's chooserPanels.
418       *
419       * @param panel The AbstractColorChooserPanel to add.
420       */
421      public void addChooserPanel(AbstractColorChooserPanel panel)
422      {
423        if (panel == null)
424          return;
425        AbstractColorChooserPanel[] old = chooserPanels;
426        AbstractColorChooserPanel[] newPanels =
427          new AbstractColorChooserPanel[(old == null) ? 1 : old.length + 1];
428        if (old != null)
429          System.arraycopy(old, 0, newPanels, 0, old.length);
430        newPanels[newPanels.length - 1] = panel;
431        chooserPanels = newPanels;
432        panel.installChooserPanel(this);
433        firePropertyChange(CHOOSER_PANELS_PROPERTY, old, newPanels);
434      } // addChooserPanel()
435    
436      /**
437       * This method removes the given AbstractColorChooserPanel from the
438       * JColorChooser's list of chooserPanels.
439       *
440       * @param panel The AbstractColorChooserPanel to remove.
441       *
442       * @return The AbstractColorChooserPanel that was removed.
443       */
444      public AbstractColorChooserPanel removeChooserPanel(AbstractColorChooserPanel panel)
445      {
446        int index = -1;
447        for (int i = 0; i < chooserPanels.length; i++)
448          if (panel == chooserPanels[i])
449            {
450              index = i;
451              break;
452            }
453    
454        if (index == -1)
455          return null;
456    
457        AbstractColorChooserPanel[] old = chooserPanels;
458        if (chooserPanels.length == 1)
459          chooserPanels = null;
460        else
461          {
462            AbstractColorChooserPanel[] newPanels =
463              new AbstractColorChooserPanel[chooserPanels.length - 1];
464            System.arraycopy(chooserPanels, 0, newPanels, 0, index);
465            System.arraycopy(chooserPanels, index, newPanels, index - 1,
466                             chooserPanels.length - index);
467            chooserPanels = newPanels;
468          }
469        panel.uninstallChooserPanel(this);
470        firePropertyChange(CHOOSER_PANELS_PROPERTY, old, chooserPanels);
471        return panel;
472      }
473    
474      /**
475       * This method sets the chooserPanels property for this JColorChooser.
476       *
477       * @param panels The new set of AbstractColorChooserPanels to use.
478       */
479      public void setChooserPanels(AbstractColorChooserPanel[] panels)
480      {
481        if (panels != chooserPanels)
482          {
483            if (chooserPanels != null)
484              for (int i = 0; i < chooserPanels.length; i++)
485                if (chooserPanels[i] != null)
486                  chooserPanels[i].uninstallChooserPanel(this);
487    
488            AbstractColorChooserPanel[] old = chooserPanels;
489            chooserPanels = panels;
490    
491            if (panels != null)
492              for (int i = 0; i < panels.length; i++)
493                if (panels[i] != null)
494                  panels[i].installChooserPanel(this);
495    
496            firePropertyChange(CHOOSER_PANELS_PROPERTY, old, chooserPanels);
497          }
498      } // setChooserPanels()
499    
500      /**
501       * This method returns the AbstractColorChooserPanels used with this
502       * JColorChooser.
503       *
504       * @return The AbstractColorChooserPanels used with this JColorChooser.
505       */
506      public AbstractColorChooserPanel[] getChooserPanels()
507      {
508        return chooserPanels;
509      } // getChooserPanels()
510    
511      /**
512       * This method returns the ColorSelectionModel used with this JColorChooser.
513       *
514       * @return The ColorSelectionModel.
515       */
516      public ColorSelectionModel getSelectionModel()
517      {
518        return selectionModel;
519      } // getSelectionModel()
520    
521      /**
522       * This method sets the ColorSelectionModel to be used with this
523       * JColorChooser.
524       *
525       * @param model The ColorSelectionModel to be used with this JColorChooser.
526       *
527       * @throws AWTError If the given model is null.
528       */
529      public void setSelectionModel(ColorSelectionModel model)
530      {
531        if (model == null)
532          throw new AWTError("ColorSelectionModel is not allowed to be null.");
533        selectionModel = model;
534      } // setSelectionModel()
535    
536      /**
537       * DOCUMENT ME!
538       *
539       * @return DOCUMENT ME!
540       */
541      public boolean getDragEnabled()
542      {
543        return dragEnabled;
544      }
545    
546      /**
547       * DOCUMENT ME!
548       *
549       * @param b DOCUMENT ME!
550       */
551      public void setDragEnabled(boolean b)
552      {
553        dragEnabled = b;
554      }
555    
556      /**
557       * This method returns a String describing the JColorChooser.
558       *
559       * @return A String describing the JColorChooser.
560       */
561      protected String paramString()
562      {
563        return "JColorChooser";
564      } // paramString()
565    
566      /**
567       * getAccessibleContext
568       *
569       * @return AccessibleContext
570       */
571      public AccessibleContext getAccessibleContext()
572      {
573        if (accessibleContext == null)
574          accessibleContext = new AccessibleJColorChooser();
575    
576        return accessibleContext;
577      }
578    
579      /**
580       * A helper class that hides a JDialog when the action is performed.
581       */
582      static class DefaultOKCancelListener implements ActionListener
583      {
584        /** The JDialog to hide. */
585        private JDialog dialog;
586    
587        /**
588         * Creates a new DefaultOKCancelListener with the given JDialog to hide.
589         *
590         * @param dialog The JDialog to hide.
591         */
592        public DefaultOKCancelListener(JDialog dialog)
593        {
594          super();
595          this.dialog = dialog;
596        }
597    
598        /**
599         * This method hides the JDialog when called.
600         *
601         * @param e The ActionEvent.
602         */
603        public void actionPerformed(ActionEvent e)
604        {
605          dialog.hide();
606        }
607      }
608    
609      /**
610       * This method resets the JColorChooser color to the initial color when the
611       * action is performed.
612       */
613      static class DefaultResetListener implements ActionListener
614      {
615        /** The JColorChooser to reset. */
616        private JColorChooser chooser;
617    
618        /** The initial color. */
619        private Color init;
620    
621        /**
622         * Creates a new DefaultResetListener with the given JColorChooser.
623         *
624         * @param chooser The JColorChooser to reset.
625         */
626        public DefaultResetListener(JColorChooser chooser)
627        {
628          super();
629          this.chooser = chooser;
630          init = chooser.getColor();
631        }
632    
633        /**
634         * This method resets the JColorChooser to its initial color.
635         *
636         * @param e The ActionEvent.
637         */
638        public void actionPerformed(ActionEvent e)
639        {
640          chooser.setColor(init);
641        }
642      }
643    
644    }