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                 XPStyle xp = XPStyle.getXP();
  95                 skin = (xp != null) ? xp.getSkin(header, Part.HP_HEADERITEM) : null;
  96             }
  97             Insets margins = (skin != null) ? skin.getContentMargin() : null;
  98             Border border = null;
  99             int contentTop = 0;
 100             int contentLeft = 0;
 101             int contentBottom = 0;
 102             int contentRight = 0;
 103             if (margins != null) {
 104                 contentTop = margins.top;
 105                 contentLeft = margins.left;
 106                 contentBottom = margins.bottom;
 107                 contentRight = margins.right;
 108             }
 109             /* idk:
 110              * Both on Vista and XP there is some offset to the
 111              * HP_HEADERITEM content. It does not seem to come from
 112              * Prop.CONTENTMARGINS. Do not know where it is defined.
 113              * using some hardcoded values.
 114              */
 115             contentLeft += 5;
 116             contentBottom += 4;
 117             contentRight += 5;
 118 
 119             /* On Vista sortIcon is painted above the header's text.
 120              * We use border to paint it.
 121              */
 122             Icon sortIcon;
 123             if (WindowsLookAndFeel.isOnVista()
 124                 && ((sortIcon = getIcon()) instanceof javax.swing.plaf.UIResource
 125                     || sortIcon == null)) {
 126                 contentTop += 1;
 127                 setIcon(null);
 128                 sortIcon = null;
 129                 SortOrder sortOrder =
 130                     getColumnSortOrder(table, column);
 131                 if (sortOrder != null) {
 132                     switch (sortOrder) {
 133                     case ASCENDING:
 134                         sortIcon =
 135                             UIManager.getIcon("Table.ascendingSortIcon");
 136                         break;
 137                     case DESCENDING:
 138                         sortIcon =
 139                             UIManager.getIcon("Table.descendingSortIcon");
 140                         break;
 141                     }
 142                 }
 143                 if (sortIcon != null) {
 144                     contentBottom = sortIcon.getIconHeight();
 145                     border = new IconBorder(sortIcon, contentTop, contentLeft,
 146                                             contentBottom, contentRight);
 147                 } else {
 148                     sortIcon =
 149                         UIManager.getIcon("Table.ascendingSortIcon");
 150                     int sortIconHeight =
 151                         (sortIcon != null) ? sortIcon.getIconHeight() : 0;
 152                     if (sortIconHeight != 0) {
 153                         contentBottom = sortIconHeight;
 154                     }
 155                     border =
 156                         new EmptyBorder(
 157                             sortIconHeight + contentTop, contentLeft,
 158                             contentBottom, contentRight);
 159                 }
 160             } else {
 161                 contentTop += 3;
 162                 border = new EmptyBorder(contentTop, contentLeft,
 163                                          contentBottom, contentRight);
 164             }
 165             setBorder(border);
 166             return this;
 167         }
 168 
 169         public void paint(Graphics g) {
 170             Dimension size = getSize();
 171             State state = State.NORMAL;
 172             TableColumn draggedColumn = header.getDraggedColumn();
 173             if (draggedColumn != null &&
 174                     column == SwingUtilities2.convertColumnIndexToView(
 175                             header.getColumnModel(), draggedColumn.getModelIndex())) {
 176                 state = State.PRESSED;
 177             } else if (isSelected || hasFocus || hasRollover) {
 178                 state = State.HOT;
 179             }
 180             /* on Vista there are more states for sorted columns */
 181             if (WindowsLookAndFeel.isOnVista()) {
 182                 SortOrder sortOrder = getColumnSortOrder(header.getTable(), column);
 183                 if (sortOrder != null) {
 184                      switch(sortOrder) {
 185                      case ASCENDING:
 186                      case DESCENDING:
 187                          switch (state) {
 188                          case NORMAL:
 189                              state = State.SORTEDNORMAL;
 190                              break;
 191                          case PRESSED:
 192                              state = State.SORTEDPRESSED;
 193                              break;
 194                          case HOT:
 195                              state = State.SORTEDHOT;
 196                              break;
 197                          default:
 198                              /* do nothing */
 199                          }
 200                          break;
 201                      default :
 202                          /* do nothing */
 203                      }
 204                 }
 205             }
 206             skin.paintSkin(g, 0, 0, size.width-1, size.height-1, state);
 207             super.paint(g);
 208         }
 209     }
 210 
 211     /**
 212      * A border with an Icon at the middle of the top side.
 213      * Outer insets can be provided for this border.
 214      */
 215     private static class IconBorder implements Border, UIResource{
 216         private final Icon icon;
 217         private final int top;
 218         private final int left;
 219         private final int bottom;
 220         private final int right;
 221         /**
 222          * Creates this border;
 223          * @param icon - icon to paint for this border
 224          * @param top, left, bottom, right - outer insets for this border
 225          */
 226         public IconBorder(Icon icon, int top, int left,
 227                           int bottom, int right) {
 228             this.icon = icon;
 229             this.top = top;
 230             this.left = left;
 231             this.bottom = bottom;
 232             this.right = right;
 233         }
 234         public Insets getBorderInsets(Component c) {
 235             return new Insets(icon.getIconHeight() + top, left, bottom, right);
 236         }
 237         public boolean isBorderOpaque() {
 238             return false;
 239         }
 240         public void paintBorder(Component c, Graphics g, int x, int y,
 241                                 int width, int height) {
 242             icon.paintIcon(c, g,
 243                 x + left + (width - left - right - icon.getIconWidth()) / 2,
 244                 y + top);
 245         }
 246     }
 247 }