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