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 
  26 package com.sun.java.swing.plaf.windows;
  27 
  28 import java.awt.*;
  29 import javax.swing.*;
  30 import javax.swing.border.*;
  31 import javax.swing.plaf.*;
  32 import javax.swing.plaf.basic.*;
  33 import javax.swing.table.*;
  34 
  35 import static com.sun.java.swing.plaf.windows.TMSchema.*;
  36 import static com.sun.java.swing.plaf.windows.XPStyle.*;
  37 import sun.swing.table.*;
  38 import sun.swing.SwingUtilities2;
  39 
  40 
  41 public class WindowsTableHeaderUI extends BasicTableHeaderUI {
  42     private TableCellRenderer originalHeaderRenderer;
  43 
  44     public static ComponentUI createUI(JComponent h) {
  45         return new WindowsTableHeaderUI();
  46     }
  47 
  48     public void installUI(JComponent c) {
  49         super.installUI(c);
  50 
  51         if (XPStyle.getXP() != null) {
  52             originalHeaderRenderer = header.getDefaultRenderer();
  53             if (originalHeaderRenderer instanceof UIResource) {
  54                 header.setDefaultRenderer(new XPDefaultRenderer());
  55             }
  56         }
  57     }
  58 
  59     public void uninstallUI(JComponent c) {
  60         if (header.getDefaultRenderer() instanceof XPDefaultRenderer) {
  61             header.setDefaultRenderer(originalHeaderRenderer);
  62         }
  63         super.uninstallUI(c);
  64     }
  65 
  66     @Override
  67     protected void rolloverColumnUpdated(int oldColumn, int newColumn) {
  68         if (XPStyle.getXP() != null) {
  69             header.repaint(header.getHeaderRect(oldColumn));
  70             header.repaint(header.getHeaderRect(newColumn));
  71         }
  72     }
  73 
  74     @SuppressWarnings("serial") // JDK-implementation class
  75     private class XPDefaultRenderer extends DefaultTableCellHeaderRenderer {
  76         Skin skin;
  77         boolean isSelected, hasFocus, hasRollover;
  78         int column;
  79 
  80         XPDefaultRenderer() {
  81             setHorizontalAlignment(LEADING);
  82         }
  83 
  84         public Component getTableCellRendererComponent(JTable table, Object value,
  85                                                        boolean isSelected, boolean hasFocus,
  86                                                        int row, int column) {
  87             super.getTableCellRendererComponent(table, value, isSelected,
  88                                                 hasFocus, row, column);
  89             this.isSelected = isSelected;
  90             this.hasFocus = hasFocus;
  91             this.column = column;
  92             this.hasRollover = (column == getRolloverColumn());
  93             if (skin == null) {
  94                 skin = XPStyle.getXP().getSkin(header, Part.HP_HEADERITEM);
  95             }
  96             Insets margins = skin.getContentMargin();
  97             Border border = null;
  98             int contentTop = 0;
  99             int contentLeft = 0;
 100             int contentBottom = 0;
 101             int contentRight = 0;
 102             if (margins != null) {
 103                 contentTop = margins.top;
 104                 contentLeft = margins.left;
 105                 contentBottom = margins.bottom;
 106                 contentRight = margins.right;
 107             }
 108             /* idk:
 109              * Both on Vista and XP there is some offset to the
 110              * HP_HEADERITEM content. It does not seem to come from
 111              * Prop.CONTENTMARGINS. Do not know where it is defined.
 112              * using some hardcoded values.
 113              */
 114             contentLeft += 5;
 115             contentBottom += 4;
 116             contentRight += 5;
 117 
 118             /* On Vista sortIcon is painted above the header's text.
 119              * We use border to paint it.
 120              */
 121             Icon sortIcon;
 122             if (WindowsLookAndFeel.isOnVista()
 123                 && ((sortIcon = getIcon()) instanceof javax.swing.plaf.UIResource
 124                     || sortIcon == null)) {
 125                 contentTop += 1;
 126                 setIcon(null);
 127                 sortIcon = null;
 128                 SortOrder sortOrder =
 129                     getColumnSortOrder(table, column);
 130                 if (sortOrder != null) {
 131                     switch (sortOrder) {
 132                     case ASCENDING:
 133                         sortIcon =
 134                             UIManager.getIcon("Table.ascendingSortIcon");
 135                         break;
 136                     case DESCENDING:
 137                         sortIcon =
 138                             UIManager.getIcon("Table.descendingSortIcon");
 139                         break;
 140                     }
 141                 }
 142                 if (sortIcon != null) {
 143                     contentBottom = sortIcon.getIconHeight();
 144                     border = new IconBorder(sortIcon, contentTop, contentLeft,
 145                                             contentBottom, contentRight);
 146                 } else {
 147                     sortIcon =
 148                         UIManager.getIcon("Table.ascendingSortIcon");
 149                     int sortIconHeight =
 150                         (sortIcon != null) ? sortIcon.getIconHeight() : 0;
 151                     if (sortIconHeight != 0) {
 152                         contentBottom = sortIconHeight;
 153                     }
 154                     border =
 155                         new EmptyBorder(
 156                             sortIconHeight + contentTop, contentLeft,
 157                             contentBottom, contentRight);
 158                 }
 159             } else {
 160                 contentTop += 3;
 161                 border = new EmptyBorder(contentTop, contentLeft,
 162                                          contentBottom, contentRight);
 163             }
 164             setBorder(border);
 165             return this;
 166         }
 167 
 168         public void paint(Graphics g) {
 169             Dimension size = getSize();
 170             State state = State.NORMAL;
 171             TableColumn draggedColumn = header.getDraggedColumn();
 172             if (draggedColumn != null &&
 173                     column == SwingUtilities2.convertColumnIndexToView(
 174                             header.getColumnModel(), draggedColumn.getModelIndex())) {
 175                 state = State.PRESSED;
 176             } else if (isSelected || hasFocus || hasRollover) {
 177                 state = State.HOT;
 178             }
 179             /* on Vista there are more states for sorted columns */
 180             if (WindowsLookAndFeel.isOnVista()) {
 181                 SortOrder sortOrder = getColumnSortOrder(header.getTable(), column);
 182                 if (sortOrder != null) {
 183                      switch(sortOrder) {
 184                      case ASCENDING:
 185                      case DESCENDING:
 186                          switch (state) {
 187                          case NORMAL:
 188                              state = State.SORTEDNORMAL;
 189                              break;
 190                          case PRESSED:
 191                              state = State.SORTEDPRESSED;
 192                              break;
 193                          case HOT:
 194                              state = State.SORTEDHOT;
 195                              break;
 196                          default:
 197                              /* do nothing */
 198                          }
 199                          break;
 200                      default :
 201                          /* do nothing */
 202                      }
 203                 }
 204             }
 205             skin.paintSkin(g, 0, 0, size.width-1, size.height-1, state);
 206             super.paint(g);
 207         }
 208     }
 209 
 210     /**
 211      * A border with an Icon at the middle of the top side.
 212      * Outer insets can be provided for this border.
 213      */
 214     private static class IconBorder implements Border, UIResource{
 215         private final Icon icon;
 216         private final int top;
 217         private final int left;
 218         private final int bottom;
 219         private final int right;
 220         /**
 221          * Creates this border;
 222          * @param icon - icon to paint for this border
 223          * @param top, left, bottom, right - outer insets for this border
 224          */
 225         public IconBorder(Icon icon, int top, int left,
 226                           int bottom, int right) {
 227             this.icon = icon;
 228             this.top = top;
 229             this.left = left;
 230             this.bottom = bottom;
 231             this.right = right;
 232         }
 233         public Insets getBorderInsets(Component c) {
 234             return new Insets(icon.getIconHeight() + top, left, bottom, right);
 235         }
 236         public boolean isBorderOpaque() {
 237             return false;
 238         }
 239         public void paintBorder(Component c, Graphics g, int x, int y,
 240                                 int width, int height) {
 241             icon.paintIcon(c, g,
 242                 x + left + (width - left - right - icon.getIconWidth()) / 2,
 243                 y + top);
 244         }
 245     }
 246 }