1 /*
2  * Copyright (c) 2002, 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 
26 package javax.swing.plaf.synth;
27 
28 import java.awt.*;
29 import java.beans.*;
30 import javax.swing.*;
31 import javax.swing.border.*;
32 import javax.swing.plaf.*;
33 import javax.swing.plaf.basic.*;
34 import javax.swing.table.*;
35 import sun.swing.table.*;
36 
37 /**
38  * Provides the Synth L&F UI delegate for
39  * {@link javax.swing.table.JTableHeader}.
40  *
41  * @author Alan Chung
42  * @author Philip Milne
43  * @since 1.7
44  */
45 public class SynthTableHeaderUI extends BasicTableHeaderUI
46                                 implements PropertyChangeListener, SynthUI {
47 
48 //
49 // Instance Variables
50 //
51 
52     private TableCellRenderer prevRenderer = null;
53 
54     private SynthStyle style;
55 
56     /**
57      * Creates a new UI object for the given component.
58      *
59      * @param h component to create UI object for
60      * @return the UI object
61      */
createUI(JComponent h)62     public static ComponentUI createUI(JComponent h) {
63         return new SynthTableHeaderUI();
64     }
65 
66     /**
67      * {@inheritDoc}
68      */
69     @Override
installDefaults()70     protected void installDefaults() {
71         prevRenderer = header.getDefaultRenderer();
72         if (prevRenderer instanceof UIResource) {
73             header.setDefaultRenderer(new HeaderRenderer());
74         }
75         updateStyle(header);
76     }
77 
updateStyle(JTableHeader c)78     private void updateStyle(JTableHeader c) {
79         SynthContext context = getContext(c, ENABLED);
80         SynthStyle oldStyle = style;
81         style = SynthLookAndFeel.updateStyle(context, this);
82         if (style != oldStyle) {
83             if (oldStyle != null) {
84                 uninstallKeyboardActions();
85                 installKeyboardActions();
86             }
87         }
88     }
89 
90     /**
91      * {@inheritDoc}
92      */
93     @Override
installListeners()94     protected void installListeners() {
95         super.installListeners();
96         header.addPropertyChangeListener(this);
97     }
98 
99     /**
100      * {@inheritDoc}
101      */
102     @Override
uninstallDefaults()103     protected void uninstallDefaults() {
104         if (header.getDefaultRenderer() instanceof HeaderRenderer) {
105             header.setDefaultRenderer(prevRenderer);
106         }
107 
108         SynthContext context = getContext(header, ENABLED);
109 
110         style.uninstallDefaults(context);
111         style = null;
112     }
113 
114     /**
115      * {@inheritDoc}
116      */
117     @Override
uninstallListeners()118     protected void uninstallListeners() {
119         header.removePropertyChangeListener(this);
120         super.uninstallListeners();
121     }
122 
123     /**
124      * Notifies this UI delegate to repaint the specified component.
125      * This method paints the component background, then calls
126      * the {@link #paint(SynthContext,Graphics)} method.
127      *
128      * <p>In general, this method does not need to be overridden by subclasses.
129      * All Look and Feel rendering code should reside in the {@code paint} method.
130      *
131      * @param g the {@code Graphics} object used for painting
132      * @param c the component being painted
133      * @see #paint(SynthContext,Graphics)
134      */
135     @Override
update(Graphics g, JComponent c)136     public void update(Graphics g, JComponent c) {
137         SynthContext context = getContext(c);
138 
139         SynthLookAndFeel.update(context, g);
140         context.getPainter().paintTableHeaderBackground(context,
141                           g, 0, 0, c.getWidth(), c.getHeight());
142         paint(context, g);
143     }
144 
145     /**
146      * Paints the specified component according to the Look and Feel.
147      * <p>This method is not used by Synth Look and Feel.
148      * Painting is handled by the {@link #paint(SynthContext,Graphics)} method.
149      *
150      * @param g the {@code Graphics} object used for painting
151      * @param c the component being painted
152      * @see #paint(SynthContext,Graphics)
153      */
154     @Override
paint(Graphics g, JComponent c)155     public void paint(Graphics g, JComponent c) {
156         SynthContext context = getContext(c);
157 
158         paint(context, g);
159     }
160 
161     /**
162      * Paints the specified component.
163      *
164      * @param context context for the component being painted
165      * @param g the {@code Graphics} object used for painting
166      * @see #update(Graphics,JComponent)
167      */
paint(SynthContext context, Graphics g)168     protected void paint(SynthContext context, Graphics g) {
169         super.paint(g, context.getComponent());
170     }
171 
172     /**
173      * {@inheritDoc}
174      */
175     @Override
paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h)176     public void paintBorder(SynthContext context, Graphics g, int x,
177                             int y, int w, int h) {
178         context.getPainter().paintTableHeaderBorder(context, g, x, y, w, h);
179     }
180 //
181 // SynthUI
182 //
183     /**
184      * {@inheritDoc}
185      */
186     @Override
getContext(JComponent c)187     public SynthContext getContext(JComponent c) {
188         return getContext(c, SynthLookAndFeel.getComponentState(c));
189     }
190 
getContext(JComponent c, int state)191     private SynthContext getContext(JComponent c, int state) {
192         return SynthContext.getContext(c, style, state);
193     }
194 
195     /**
196      * {@inheritDoc}
197      */
198     @Override
rolloverColumnUpdated(int oldColumn, int newColumn)199     protected void rolloverColumnUpdated(int oldColumn, int newColumn) {
200         header.repaint(header.getHeaderRect(oldColumn));
201         header.repaint(header.getHeaderRect(newColumn));
202     }
203 
204     /**
205      * {@inheritDoc}
206      */
207     @Override
propertyChange(PropertyChangeEvent evt)208     public void propertyChange(PropertyChangeEvent evt) {
209         if (SynthLookAndFeel.shouldUpdateStyle(evt)) {
210             updateStyle((JTableHeader)evt.getSource());
211         }
212     }
213 
214     @SuppressWarnings("serial") // Superclass is not serializable across versions
215     private class HeaderRenderer extends DefaultTableCellHeaderRenderer {
HeaderRenderer()216         HeaderRenderer() {
217             setHorizontalAlignment(JLabel.LEADING);
218             setName("TableHeader.renderer");
219         }
220 
221         @Override
getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)222         public Component getTableCellRendererComponent(JTable table, Object value,
223                                                        boolean isSelected,
224                                                        boolean hasFocus,
225                                                        int row, int column) {
226 
227             boolean hasRollover = (column == getRolloverColumn());
228             if (isSelected || hasRollover || hasFocus) {
229                 boolean enabled = (table == null)? true : table.isEnabled();
230                 SynthLookAndFeel.setSelectedUI((SynthLabelUI)SynthLookAndFeel.
231                              getUIOfType(getUI(), SynthLabelUI.class),
232                              isSelected, hasFocus, enabled,
233                              hasRollover);
234             } else {
235                 SynthLookAndFeel.resetSelectedUI();
236             }
237 
238             //stuff a variable into the client property of this renderer indicating the sort order,
239             //so that different rendering can be done for the header based on sorted state.
240             RowSorter<?> rs = table == null ? null : table.getRowSorter();
241             java.util.List<? extends RowSorter.SortKey> sortKeys = rs == null ? null : rs.getSortKeys();
242             if (sortKeys != null && sortKeys.size() > 0 && sortKeys.get(0).getColumn() ==
243                     table.convertColumnIndexToModel(column)) {
244                 switch(sortKeys.get(0).getSortOrder()) {
245                     case ASCENDING:
246                         putClientProperty("Table.sortOrder", "ASCENDING");
247                         break;
248                     case DESCENDING:
249                         putClientProperty("Table.sortOrder", "DESCENDING");
250                         break;
251                     case UNSORTED:
252                         putClientProperty("Table.sortOrder", "UNSORTED");
253                         break;
254                     default:
255                         throw new AssertionError("Cannot happen");
256                 }
257             } else {
258                 putClientProperty("Table.sortOrder", "UNSORTED");
259             }
260 
261             super.getTableCellRendererComponent(table, value, isSelected,
262                                                 hasFocus, row, column);
263 
264             return this;
265         }
266 
267         @Override
setBorder(Border border)268         public void setBorder(Border border) {
269             if (border instanceof SynthBorder) {
270                 super.setBorder(border);
271             }
272         }
273     }
274 }
275