1/*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.swing.plaf.basic;
27
28import javax.swing.*;
29import javax.swing.colorchooser.*;
30import javax.swing.event.*;
31import javax.swing.border.*;
32import javax.swing.plaf.*;
33import java.awt.*;
34import java.awt.event.*;
35import java.beans.PropertyChangeEvent;
36import java.beans.PropertyChangeListener;
37
38import sun.swing.DefaultLookup;
39
40/**
41 * Provides the basic look and feel for a JColorChooser.
42 *
43 * @author Tom Santos
44 * @author Steve Wilson
45 */
46
47public class BasicColorChooserUI extends ColorChooserUI
48{
49    /**
50     * JColorChooser this BasicColorChooserUI is installed on.
51     *
52     * @since 1.5
53     */
54    protected JColorChooser chooser;
55
56    JTabbedPane tabbedPane;
57    JPanel singlePanel;
58
59    JPanel previewPanelHolder;
60    JComponent previewPanel;
61    boolean isMultiPanel = false;
62    private static TransferHandler defaultTransferHandler = new ColorTransferHandler();
63
64    /**
65     * The array of default color choosers.
66     */
67    protected AbstractColorChooserPanel[] defaultChoosers;
68
69    /**
70     * The instance of {@code ChangeListener}.
71     */
72    protected ChangeListener previewListener;
73
74    /**
75     * The instance of {@code PropertyChangeListener}.
76     */
77    protected PropertyChangeListener propertyChangeListener;
78    private Handler handler;
79
80    /**
81     * Returns a new instance of {@code BasicColorChooserUI}.
82     *
83     * @param c a component
84     * @return a new instance of {@code BasicColorChooserUI}
85     */
86    public static ComponentUI createUI(JComponent c) {
87        return new BasicColorChooserUI();
88    }
89
90    /**
91     * Returns an array of default color choosers.
92     *
93     * @return an array of default color choosers
94     */
95    protected AbstractColorChooserPanel[] createDefaultChoosers() {
96        AbstractColorChooserPanel[] panels = ColorChooserComponentFactory.getDefaultChooserPanels();
97        return panels;
98    }
99
100    /**
101     * Uninstalls default color choosers.
102     */
103    protected void uninstallDefaultChoosers() {
104        AbstractColorChooserPanel[] choosers = chooser.getChooserPanels();
105        for( int i = 0 ; i < choosers.length; i++) {
106            chooser.removeChooserPanel( choosers[i] );
107        }
108    }
109
110    public void installUI( JComponent c ) {
111        chooser = (JColorChooser)c;
112
113        super.installUI( c );
114
115        installDefaults();
116        installListeners();
117
118        tabbedPane = new JTabbedPane();
119        tabbedPane.setName("ColorChooser.tabPane");
120        tabbedPane.setInheritsPopupMenu(true);
121        tabbedPane.getAccessibleContext().setAccessibleDescription(tabbedPane.getName());
122        singlePanel = new JPanel(new CenterLayout());
123        singlePanel.setName("ColorChooser.panel");
124        singlePanel.setInheritsPopupMenu(true);
125
126        chooser.setLayout( new BorderLayout() );
127
128        defaultChoosers = createDefaultChoosers();
129        chooser.setChooserPanels(defaultChoosers);
130
131        previewPanelHolder = new JPanel(new CenterLayout());
132        previewPanelHolder.setName("ColorChooser.previewPanelHolder");
133
134        if (DefaultLookup.getBoolean(chooser, this,
135                                  "ColorChooser.showPreviewPanelText", true)) {
136            String previewString = UIManager.getString(
137                "ColorChooser.previewText", chooser.getLocale());
138            previewPanelHolder.setBorder(new TitledBorder(previewString));
139        }
140        previewPanelHolder.setInheritsPopupMenu(true);
141
142        installPreviewPanel();
143        chooser.applyComponentOrientation(c.getComponentOrientation());
144    }
145
146    public void uninstallUI( JComponent c ) {
147        chooser.remove(tabbedPane);
148        chooser.remove(singlePanel);
149        chooser.remove(previewPanelHolder);
150
151        uninstallDefaultChoosers();
152        uninstallListeners();
153        uninstallPreviewPanel();
154        uninstallDefaults();
155
156        previewPanelHolder = null;
157        previewPanel = null;
158        defaultChoosers = null;
159        chooser = null;
160        tabbedPane = null;
161
162        handler = null;
163    }
164
165    /**
166     * Installs preview panel.
167     */
168    protected void installPreviewPanel() {
169        JComponent previewPanel = this.chooser.getPreviewPanel();
170        if (previewPanel == null) {
171            previewPanel = ColorChooserComponentFactory.getPreviewPanel();
172        }
173        else if (JPanel.class.equals(previewPanel.getClass()) && (0 == previewPanel.getComponentCount())) {
174            previewPanel = null;
175        }
176        this.previewPanel = previewPanel;
177        if (previewPanel != null) {
178            chooser.add(previewPanelHolder, BorderLayout.SOUTH);
179            previewPanel.setForeground(chooser.getColor());
180            previewPanelHolder.add(previewPanel);
181            previewPanel.addMouseListener(getHandler());
182            previewPanel.setInheritsPopupMenu(true);
183        }
184    }
185
186    /**
187     * Removes installed preview panel from the UI delegate.
188     *
189     * @since 1.7
190     */
191    protected void uninstallPreviewPanel() {
192        if (this.previewPanel != null) {
193            this.previewPanel.removeMouseListener(getHandler());
194            this.previewPanelHolder.remove(this.previewPanel);
195        }
196        this.chooser.remove(this.previewPanelHolder);
197    }
198
199    /**
200     * Installs default properties.
201     */
202    protected void installDefaults() {
203        LookAndFeel.installColorsAndFont(chooser, "ColorChooser.background",
204                                              "ColorChooser.foreground",
205                                              "ColorChooser.font");
206        LookAndFeel.installProperty(chooser, "opaque", Boolean.TRUE);
207        TransferHandler th = chooser.getTransferHandler();
208        if (th == null || th instanceof UIResource) {
209            chooser.setTransferHandler(defaultTransferHandler);
210        }
211    }
212
213    /**
214     * Uninstalls default properties.
215     */
216    protected void uninstallDefaults() {
217        if (chooser.getTransferHandler() instanceof UIResource) {
218            chooser.setTransferHandler(null);
219        }
220    }
221
222    /**
223     * Registers listeners.
224     */
225    protected void installListeners() {
226        propertyChangeListener = createPropertyChangeListener();
227        chooser.addPropertyChangeListener(propertyChangeListener);
228
229        previewListener = getHandler();
230        chooser.getSelectionModel().addChangeListener(previewListener);
231    }
232
233    private Handler getHandler() {
234        if (handler == null) {
235            handler = new Handler();
236        }
237        return handler;
238    }
239
240    /**
241     * Returns an instance of {@code PropertyChangeListener}.
242     *
243     * @return an instance of {@code PropertyChangeListener}
244     */
245    protected PropertyChangeListener createPropertyChangeListener() {
246        return getHandler();
247    }
248
249    /**
250     * Unregisters listeners.
251     */
252    protected void uninstallListeners() {
253        chooser.removePropertyChangeListener( propertyChangeListener );
254        chooser.getSelectionModel().removeChangeListener(previewListener);
255        previewListener = null;
256    }
257
258    private void selectionChanged(ColorSelectionModel model) {
259        JComponent previewPanel = this.chooser.getPreviewPanel();
260        if (previewPanel != null) {
261            previewPanel.setForeground(model.getSelectedColor());
262            previewPanel.repaint();
263        }
264        AbstractColorChooserPanel[] panels = this.chooser.getChooserPanels();
265        if (panels != null) {
266            for (AbstractColorChooserPanel panel : panels) {
267                if (panel != null) {
268                    panel.updateChooser();
269                }
270            }
271        }
272    }
273
274    private class Handler implements ChangeListener, MouseListener,
275            PropertyChangeListener {
276        //
277        // ChangeListener
278        //
279        public void stateChanged(ChangeEvent evt) {
280            selectionChanged((ColorSelectionModel) evt.getSource());
281        }
282
283        //
284        // MouseListener
285        public void mousePressed(MouseEvent evt) {
286            if (chooser.getDragEnabled()) {
287                TransferHandler th = chooser.getTransferHandler();
288                th.exportAsDrag(chooser, evt, TransferHandler.COPY);
289            }
290        }
291        public void mouseReleased(MouseEvent evt) {}
292        public void mouseClicked(MouseEvent evt) {}
293        public void mouseEntered(MouseEvent evt) {}
294        public void mouseExited(MouseEvent evt) {}
295
296        //
297        // PropertyChangeListener
298        //
299        public void propertyChange(PropertyChangeEvent evt) {
300            String prop = evt.getPropertyName();
301
302            if (prop == JColorChooser.CHOOSER_PANELS_PROPERTY) {
303                AbstractColorChooserPanel[] oldPanels =
304                    (AbstractColorChooserPanel[])evt.getOldValue();
305                AbstractColorChooserPanel[] newPanels =
306                    (AbstractColorChooserPanel[])evt.getNewValue();
307
308                for (int i = 0; i < oldPanels.length; i++) {  // remove old panels
309                   Container wrapper = oldPanels[i].getParent();
310                    if (wrapper != null) {
311                      Container parent = wrapper.getParent();
312                      if (parent != null)
313                          parent.remove(wrapper);  // remove from hierarchy
314                      oldPanels[i].uninstallChooserPanel(chooser); // uninstall
315                    }
316                }
317
318                int numNewPanels = newPanels.length;
319                if (numNewPanels == 0) {  // removed all panels and added none
320                    chooser.remove(tabbedPane);
321                    return;
322                }
323                else if (numNewPanels == 1) {  // one panel case
324                    chooser.remove(tabbedPane);
325                    JPanel centerWrapper = new JPanel( new CenterLayout() );
326                    centerWrapper.setInheritsPopupMenu(true);
327                    centerWrapper.add(newPanels[0]);
328                    singlePanel.add(centerWrapper, BorderLayout.CENTER);
329                    chooser.add(singlePanel);
330                }
331                else {   // multi-panel case
332                    if ( oldPanels.length < 2 ) {// moving from single to multiple
333                        chooser.remove(singlePanel);
334                        chooser.add(tabbedPane, BorderLayout.CENTER);
335                    }
336
337                    for (int i = 0; i < newPanels.length; i++) {
338                        JPanel centerWrapper = new JPanel( new CenterLayout() );
339                        centerWrapper.setInheritsPopupMenu(true);
340                        String name = newPanels[i].getDisplayName();
341                        int mnemonic = newPanels[i].getMnemonic();
342                        centerWrapper.add(newPanels[i]);
343                        tabbedPane.addTab(name, centerWrapper);
344                        if (mnemonic > 0) {
345                            tabbedPane.setMnemonicAt(i, mnemonic);
346                            int index = newPanels[i].getDisplayedMnemonicIndex();
347                            if (index >= 0) {
348                                tabbedPane.setDisplayedMnemonicIndexAt(i, index);
349                            }
350                        }
351                    }
352                }
353                chooser.applyComponentOrientation(chooser.getComponentOrientation());
354                for (int i = 0; i < newPanels.length; i++) {
355                    newPanels[i].installChooserPanel(chooser);
356                }
357            }
358            else if (prop == JColorChooser.PREVIEW_PANEL_PROPERTY) {
359                uninstallPreviewPanel();
360                installPreviewPanel();
361            }
362            else if (prop == JColorChooser.SELECTION_MODEL_PROPERTY) {
363                ColorSelectionModel oldModel = (ColorSelectionModel) evt.getOldValue();
364                oldModel.removeChangeListener(previewListener);
365                ColorSelectionModel newModel = (ColorSelectionModel) evt.getNewValue();
366                newModel.addChangeListener(previewListener);
367                selectionChanged(newModel);
368            }
369            else if (prop == "componentOrientation") {
370                ComponentOrientation o =
371                    (ComponentOrientation)evt.getNewValue();
372                JColorChooser cc = (JColorChooser)evt.getSource();
373                if (o != (ComponentOrientation)evt.getOldValue()) {
374                    cc.applyComponentOrientation(o);
375                    cc.updateUI();
376                }
377            }
378        }
379    }
380
381    /**
382     * This class should be treated as a &quot;protected&quot; inner class.
383     * Instantiate it only within subclasses of {@code BasicColorChooserUI}.
384     */
385    public class PropertyHandler implements PropertyChangeListener {
386        public void propertyChange(PropertyChangeEvent e) {
387            getHandler().propertyChange(e);
388        }
389    }
390
391    @SuppressWarnings("serial") // JDK-implementation class
392    static class ColorTransferHandler extends TransferHandler implements UIResource {
393
394        ColorTransferHandler() {
395            super("color");
396        }
397    }
398}
399