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