Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2010, 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.basic;
   27   
   28   import java.awt;
   29   import java.awt.event;
   30   import java.util;
   31   import javax.swing;
   32   import javax.swing.event;
   33   import javax.swing.plaf;
   34   import javax.swing.table;
   35   
   36   import sun.swing;
   37   
   38   /**
   39    * BasicTableHeaderUI implementation
   40    *
   41    * @author Alan Chung
   42    * @author Philip Milne
   43    */
   44   public class BasicTableHeaderUI extends TableHeaderUI {
   45   
   46       private static Cursor resizeCursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
   47   
   48   //
   49   // Instance Variables
   50   //
   51   
   52       /** The JTableHeader that is delegating the painting to this UI. */
   53       protected JTableHeader header;
   54       protected CellRendererPane rendererPane;
   55   
   56       // Listeners that are attached to the JTable
   57       protected MouseInputListener mouseInputListener;
   58   
   59       // The column header over which the mouse currently is.
   60       private int rolloverColumn = -1;
   61   
   62       // The column that should be highlighted when the table header has the focus.
   63       private int selectedColumnIndex = 0; // Read ONLY via getSelectedColumnIndex!
   64   
   65       private static FocusListener focusListener = new FocusListener() {
   66           public void focusGained(FocusEvent e) {
   67               repaintHeader(e.getSource());
   68           }
   69   
   70           public void focusLost(FocusEvent e) {
   71               repaintHeader(e.getSource());
   72           }
   73   
   74           private void repaintHeader(Object source) {
   75               if (source instanceof JTableHeader) {
   76                   JTableHeader th = (JTableHeader)source;
   77                   BasicTableHeaderUI ui =
   78                      (BasicTableHeaderUI)BasicLookAndFeel.
   79                                           getUIOfType(th.getUI(),
   80                                               BasicTableHeaderUI.class);
   81                   if (ui == null) {
   82                       return;
   83                   }
   84   
   85                   th.repaint(th.getHeaderRect(ui.getSelectedColumnIndex()));
   86               }
   87           }
   88       };
   89   
   90       /**
   91        * This class should be treated as a "protected" inner class.
   92        * Instantiate it only within subclasses of {@code BasicTableHeaderUI}.
   93        */
   94       public class MouseInputHandler implements MouseInputListener {
   95   
   96           private int mouseXOffset;
   97           private Cursor otherCursor = resizeCursor;
   98   
   99           public void mouseClicked(MouseEvent e) {
  100               if (!header.isEnabled()) {
  101                   return;
  102               }
  103               if (e.getClickCount() % 2 == 1 &&
  104                       SwingUtilities.isLeftMouseButton(e)) {
  105                   JTable table = header.getTable();
  106                   RowSorter sorter;
  107                   if (table != null && (sorter = table.getRowSorter()) != null) {
  108                       int columnIndex = header.columnAtPoint(e.getPoint());
  109                       if (columnIndex != -1) {
  110                           columnIndex = table.convertColumnIndexToModel(
  111                                   columnIndex);
  112                           sorter.toggleSortOrder(columnIndex);
  113                       }
  114                   }
  115               }
  116           }
  117   
  118           private TableColumn getResizingColumn(Point p) {
  119               return getResizingColumn(p, header.columnAtPoint(p));
  120           }
  121   
  122           private TableColumn getResizingColumn(Point p, int column) {
  123               if (column == -1) {
  124                    return null;
  125               }
  126               Rectangle r = header.getHeaderRect(column);
  127               r.grow(-3, 0);
  128               if (r.contains(p)) {
  129                   return null;
  130               }
  131               int midPoint = r.x + r.width/2;
  132               int columnIndex;
  133               if( header.getComponentOrientation().isLeftToRight() ) {
  134                   columnIndex = (p.x < midPoint) ? column - 1 : column;
  135               } else {
  136                   columnIndex = (p.x < midPoint) ? column : column - 1;
  137               }
  138               if (columnIndex == -1) {
  139                   return null;
  140               }
  141               return header.getColumnModel().getColumn(columnIndex);
  142           }
  143   
  144           public void mousePressed(MouseEvent e) {
  145               if (!header.isEnabled()) {
  146                   return;
  147               }
  148               header.setDraggedColumn(null);
  149               header.setResizingColumn(null);
  150               header.setDraggedDistance(0);
  151   
  152               Point p = e.getPoint();
  153   
  154               // First find which header cell was hit
  155               TableColumnModel columnModel = header.getColumnModel();
  156               int index = header.columnAtPoint(p);
  157   
  158               if (index != -1) {
  159                   // The last 3 pixels + 3 pixels of next column are for resizing
  160                   TableColumn resizingColumn = getResizingColumn(p, index);
  161                   if (canResize(resizingColumn, header)) {
  162                       header.setResizingColumn(resizingColumn);
  163                       if( header.getComponentOrientation().isLeftToRight() ) {
  164                           mouseXOffset = p.x - resizingColumn.getWidth();
  165                       } else {
  166                           mouseXOffset = p.x + resizingColumn.getWidth();
  167                       }
  168                   }
  169                   else if (header.getReorderingAllowed()) {
  170                       TableColumn hitColumn = columnModel.getColumn(index);
  171                       header.setDraggedColumn(hitColumn);
  172                       mouseXOffset = p.x;
  173                   }
  174               }
  175   
  176               if (header.getReorderingAllowed()) {
  177                   int oldRolloverColumn = rolloverColumn;
  178                   rolloverColumn = -1;
  179                   rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
  180               }
  181           }
  182   
  183           private void swapCursor() {
  184               Cursor tmp = header.getCursor();
  185               header.setCursor(otherCursor);
  186               otherCursor = tmp;
  187           }
  188   
  189           public void mouseMoved(MouseEvent e) {
  190               if (!header.isEnabled()) {
  191                   return;
  192               }
  193               if (canResize(getResizingColumn(e.getPoint()), header) !=
  194                   (header.getCursor() == resizeCursor)) {
  195                   swapCursor();
  196               }
  197               updateRolloverColumn(e);
  198          }
  199   
  200           public void mouseDragged(MouseEvent e) {
  201               if (!header.isEnabled()) {
  202                   return;
  203               }
  204               int mouseX = e.getX();
  205   
  206               TableColumn resizingColumn  = header.getResizingColumn();
  207               TableColumn draggedColumn  = header.getDraggedColumn();
  208   
  209               boolean headerLeftToRight = header.getComponentOrientation().isLeftToRight();
  210   
  211               if (resizingColumn != null) {
  212                   int oldWidth = resizingColumn.getWidth();
  213                   int newWidth;
  214                   if (headerLeftToRight) {
  215                       newWidth = mouseX - mouseXOffset;
  216                   } else  {
  217                       newWidth = mouseXOffset - mouseX;
  218                   }
  219                   mouseXOffset += changeColumnWidth(resizingColumn, header,
  220                                                     oldWidth, newWidth);
  221               }
  222               else if (draggedColumn != null) {
  223                   TableColumnModel cm = header.getColumnModel();
  224                   int draggedDistance = mouseX - mouseXOffset;
  225                   int direction = (draggedDistance < 0) ? -1 : 1;
  226                   int columnIndex = viewIndexForColumn(draggedColumn);
  227                   int newColumnIndex = columnIndex + (headerLeftToRight ? direction : -direction);
  228                   if (0 <= newColumnIndex && newColumnIndex < cm.getColumnCount()) {
  229                       int width = cm.getColumn(newColumnIndex).getWidth();
  230                       if (Math.abs(draggedDistance) > (width / 2)) {
  231   
  232                           mouseXOffset = mouseXOffset + direction * width;
  233                           header.setDraggedDistance(draggedDistance - direction * width);
  234   
  235                           //Cache the selected column.
  236                           int selectedIndex =
  237                                   SwingUtilities2.convertColumnIndexToModel(
  238                                           header.getColumnModel(),
  239                                           getSelectedColumnIndex());
  240   
  241                           //Now do the move.
  242                           cm.moveColumn(columnIndex, newColumnIndex);
  243   
  244                           //Update the selected index.
  245                           selectColumn(
  246                               SwingUtilities2.convertColumnIndexToView(
  247                                       header.getColumnModel(), selectedIndex),
  248                               false);
  249   
  250                           return;
  251                       }
  252                   }
  253                   setDraggedDistance(draggedDistance, columnIndex);
  254               }
  255   
  256               updateRolloverColumn(e);
  257           }
  258   
  259           public void mouseReleased(MouseEvent e) {
  260               if (!header.isEnabled()) {
  261                   return;
  262               }
  263               setDraggedDistance(0, viewIndexForColumn(header.getDraggedColumn()));
  264   
  265               header.setResizingColumn(null);
  266               header.setDraggedColumn(null);
  267   
  268               updateRolloverColumn(e);
  269           }
  270   
  271           public void mouseEntered(MouseEvent e) {
  272               if (!header.isEnabled()) {
  273                   return;
  274               }
  275               updateRolloverColumn(e);
  276           }
  277   
  278           public void mouseExited(MouseEvent e) {
  279               if (!header.isEnabled()) {
  280                   return;
  281               }
  282               int oldRolloverColumn = rolloverColumn;
  283               rolloverColumn = -1;
  284               rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
  285           }
  286   //
  287   // Protected & Private Methods
  288   //
  289   
  290           private void setDraggedDistance(int draggedDistance, int column) {
  291               header.setDraggedDistance(draggedDistance);
  292               if (column != -1) {
  293                   header.getColumnModel().moveColumn(column, column);
  294               }
  295           }
  296       }
  297   
  298   //
  299   //  Factory methods for the Listeners
  300   //
  301   
  302       /**
  303        * Creates the mouse listener for the JTableHeader.
  304        */
  305       protected MouseInputListener createMouseInputListener() {
  306           return new MouseInputHandler();
  307       }
  308   
  309   //
  310   //  The installation/uninstall procedures and support
  311   //
  312   
  313       public static ComponentUI createUI(JComponent h) {
  314           return new BasicTableHeaderUI();
  315       }
  316   
  317   //  Installation
  318   
  319       public void installUI(JComponent c) {
  320           header = (JTableHeader)c;
  321   
  322           rendererPane = new CellRendererPane();
  323           header.add(rendererPane);
  324   
  325           installDefaults();
  326           installListeners();
  327           installKeyboardActions();
  328       }
  329   
  330       /**
  331        * Initializes JTableHeader properties such as font, foreground, and background.
  332        * The font, foreground, and background properties are only set if their
  333        * current value is either null or a UIResource, other properties are set
  334        * if the current value is null.
  335        *
  336        * @see #installUI
  337        */
  338       protected void installDefaults() {
  339           LookAndFeel.installColorsAndFont(header, "TableHeader.background",
  340                                            "TableHeader.foreground", "TableHeader.font");
  341           LookAndFeel.installProperty(header, "opaque", Boolean.TRUE);
  342       }
  343   
  344       /**
  345        * Attaches listeners to the JTableHeader.
  346        */
  347       protected void installListeners() {
  348           mouseInputListener = createMouseInputListener();
  349   
  350           header.addMouseListener(mouseInputListener);
  351           header.addMouseMotionListener(mouseInputListener);
  352           header.addFocusListener(focusListener);
  353       }
  354   
  355       /**
  356        * Register all keyboard actions on the JTableHeader.
  357        */
  358       protected void installKeyboardActions() {
  359           InputMap keyMap = (InputMap)DefaultLookup.get(header, this,
  360                   "TableHeader.ancestorInputMap");
  361           SwingUtilities.replaceUIInputMap(header,
  362                                   JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
  363           LazyActionMap.installLazyActionMap(header, BasicTableHeaderUI.class,
  364                   "TableHeader.actionMap");
  365       }
  366   
  367   // Uninstall methods
  368   
  369       public void uninstallUI(JComponent c) {
  370           uninstallDefaults();
  371           uninstallListeners();
  372           uninstallKeyboardActions();
  373   
  374           header.remove(rendererPane);
  375           rendererPane = null;
  376           header = null;
  377       }
  378   
  379       protected void uninstallDefaults() {}
  380   
  381       protected void uninstallListeners() {
  382           header.removeMouseListener(mouseInputListener);
  383           header.removeMouseMotionListener(mouseInputListener);
  384   
  385           mouseInputListener = null;
  386       }
  387   
  388       /**
  389        * Unregisters default key actions.
  390        */
  391       protected void uninstallKeyboardActions() {
  392           SwingUtilities.replaceUIInputMap(header, JComponent.WHEN_FOCUSED, null);
  393           SwingUtilities.replaceUIActionMap(header, null);
  394       }
  395   
  396       /**
  397        * Populates TableHeader's actions.
  398        */
  399       static void loadActionMap(LazyActionMap map) {
  400           map.put(new Actions(Actions.TOGGLE_SORT_ORDER));
  401           map.put(new Actions(Actions.SELECT_COLUMN_TO_LEFT));
  402           map.put(new Actions(Actions.SELECT_COLUMN_TO_RIGHT));
  403           map.put(new Actions(Actions.MOVE_COLUMN_LEFT));
  404           map.put(new Actions(Actions.MOVE_COLUMN_RIGHT));
  405           map.put(new Actions(Actions.RESIZE_LEFT));
  406           map.put(new Actions(Actions.RESIZE_RIGHT));
  407           map.put(new Actions(Actions.FOCUS_TABLE));
  408       }
  409   
  410   //
  411   // Support for mouse rollover
  412   //
  413   
  414       /**
  415        * Returns the index of the column header over which the mouse
  416        * currently is. When the mouse is not over the table header,
  417        * -1 is returned.
  418        *
  419        * @see #rolloverColumnUpdated(int, int)
  420        * @return the index of the current rollover column
  421        * @since 1.6
  422        */
  423       protected int getRolloverColumn() {
  424           return rolloverColumn;
  425       }
  426   
  427       /**
  428        * This method gets called every time when a rollover column in the table
  429        * header is updated. Every look and feel that supports a rollover effect
  430        * in a table header should override this method and repaint the header.
  431        *
  432        * @param oldColumn the index of the previous rollover column or -1 if the
  433        * mouse was not over a column
  434        * @param newColumn the index of the new rollover column or -1 if the mouse
  435        * is not over a column
  436        * @see #getRolloverColumn()
  437        * @see JTableHeader#getHeaderRect(int)
  438        * @since 1.6
  439        */
  440       protected void rolloverColumnUpdated(int oldColumn, int newColumn) {
  441       }
  442   
  443       private void updateRolloverColumn(MouseEvent e) {
  444           if (header.getDraggedColumn() == null &&
  445               header.contains(e.getPoint())) {
  446   
  447               int col = header.columnAtPoint(e.getPoint());
  448               if (col != rolloverColumn) {
  449                   int oldRolloverColumn = rolloverColumn;
  450                   rolloverColumn = col;
  451                   rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
  452               }
  453           }
  454       }
  455   
  456   //
  457   // Support for keyboard and mouse access
  458   //
  459       private int selectNextColumn(boolean doIt) {
  460           int newIndex = getSelectedColumnIndex();
  461           if (newIndex < header.getColumnModel().getColumnCount() - 1) {
  462               newIndex++;
  463               if (doIt) {
  464                   selectColumn(newIndex);
  465               }
  466           }
  467           return newIndex;
  468       }
  469   
  470       private int selectPreviousColumn(boolean doIt) {
  471           int newIndex = getSelectedColumnIndex();
  472           if (newIndex > 0) {
  473               newIndex--;
  474               if (doIt) {
  475                   selectColumn(newIndex);
  476               }
  477           }
  478           return newIndex;
  479       }
  480   
  481       /**
  482        * Selects the specified column in the table header. Repaints the
  483        * affected header cells and makes sure the newly selected one is visible.
  484        */
  485       void selectColumn(int newColIndex) {
  486           selectColumn(newColIndex, true);
  487       }
  488   
  489       void selectColumn(int newColIndex, boolean doScroll) {
  490           Rectangle repaintRect = header.getHeaderRect(selectedColumnIndex);
  491           header.repaint(repaintRect);
  492           selectedColumnIndex = newColIndex;
  493           repaintRect = header.getHeaderRect(newColIndex);
  494           header.repaint(repaintRect);
  495           if (doScroll) {
  496               scrollToColumn(newColIndex);
  497           }
  498           return;
  499       }
  500       /**
  501        * Used by selectColumn to scroll horizontally, if necessary,
  502        * to ensure that the newly selected column is visible.
  503        */
  504       private void scrollToColumn(int col) {
  505           Container container;
  506           JTable table;
  507   
  508           //Test whether the header is in a scroll pane and has a table.
  509           if ((header.getParent() == null) ||
  510               ((container = header.getParent().getParent()) == null) ||
  511               !(container instanceof JScrollPane) ||
  512               ((table = header.getTable()) == null)) {
  513               return;
  514           }
  515   
  516           //Now scroll, if necessary.
  517           Rectangle vis = table.getVisibleRect();
  518           Rectangle cellBounds = table.getCellRect(0, col, true);
  519           vis.x = cellBounds.x;
  520           vis.width = cellBounds.width;
  521           table.scrollRectToVisible(vis);
  522       }
  523   
  524       private int getSelectedColumnIndex() {
  525           int numCols = header.getColumnModel().getColumnCount();
  526           if (selectedColumnIndex >= numCols && numCols > 0) {
  527               selectedColumnIndex = numCols - 1;
  528           }
  529           return selectedColumnIndex;
  530       }
  531   
  532       private static boolean canResize(TableColumn column,
  533                                        JTableHeader header) {
  534           return (column != null) && header.getResizingAllowed()
  535                                   && column.getResizable();
  536       }
  537   
  538       private int changeColumnWidth(TableColumn resizingColumn,
  539                                     JTableHeader th,
  540                                     int oldWidth, int newWidth) {
  541           resizingColumn.setWidth(newWidth);
  542   
  543           Container container;
  544           JTable table;
  545   
  546           if ((th.getParent() == null) ||
  547               ((container = th.getParent().getParent()) == null) ||
  548               !(container instanceof JScrollPane) ||
  549               ((table = th.getTable()) == null)) {
  550               return 0;
  551           }
  552   
  553           if (!container.getComponentOrientation().isLeftToRight() &&
  554                   !th.getComponentOrientation().isLeftToRight()) {
  555                   JViewport viewport = ((JScrollPane)container).getViewport();
  556                   int viewportWidth = viewport.getWidth();
  557                   int diff = newWidth - oldWidth;
  558                   int newHeaderWidth = table.getWidth() + diff;
  559   
  560                   /* Resize a table */
  561                   Dimension tableSize = table.getSize();
  562                   tableSize.width += diff;
  563                   table.setSize(tableSize);
  564   
  565                   /* If this table is in AUTO_RESIZE_OFF mode and
  566                    * has a horizontal scrollbar, we need to update
  567                    * a view's position.
  568                    */
  569                   if ((newHeaderWidth >= viewportWidth) &&
  570                       (table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF)) {
  571                       Point p = viewport.getViewPosition();
  572                       p.x = Math.max(0, Math.min(newHeaderWidth - viewportWidth,
  573                                                  p.x + diff));
  574                       viewport.setViewPosition(p);
  575                       return diff;
  576               }
  577           }
  578           return 0;
  579       }
  580   
  581   //
  582   // Baseline
  583   //
  584   
  585       /**
  586        * Returns the baseline.
  587        *
  588        * @throws NullPointerException {@inheritDoc}
  589        * @throws IllegalArgumentException {@inheritDoc}
  590        * @see javax.swing.JComponent#getBaseline(int, int)
  591        * @since 1.6
  592        */
  593       public int getBaseline(JComponent c, int width, int height) {
  594           super.getBaseline(c, width, height);
  595           int baseline = -1;
  596           TableColumnModel columnModel = header.getColumnModel();
  597           for(int column = 0; column < columnModel.getColumnCount();
  598               column++) {
  599               TableColumn aColumn = columnModel.getColumn(column);
  600               Component comp = getHeaderRenderer(column);
  601               Dimension pref = comp.getPreferredSize();
  602               int columnBaseline = comp.getBaseline(pref.width, height);
  603               if (columnBaseline >= 0) {
  604                   if (baseline == -1) {
  605                       baseline = columnBaseline;
  606                   }
  607                   else if (baseline != columnBaseline) {
  608                       baseline = -1;
  609                       break;
  610                   }
  611               }
  612           }
  613           return baseline;
  614       }
  615   
  616   //
  617   // Paint Methods and support
  618   //
  619   
  620       public void paint(Graphics g, JComponent c) {
  621           if (header.getColumnModel().getColumnCount() <= 0) {
  622               return;
  623           }
  624           boolean ltr = header.getComponentOrientation().isLeftToRight();
  625   
  626           Rectangle clip = g.getClipBounds();
  627           Point left = clip.getLocation();
  628           Point right = new Point( clip.x + clip.width - 1, clip.y );
  629           TableColumnModel cm = header.getColumnModel();
  630           int cMin = header.columnAtPoint( ltr ? left : right );
  631           int cMax = header.columnAtPoint( ltr ? right : left );
  632           // This should never happen.
  633           if (cMin == -1) {
  634               cMin =  0;
  635           }
  636           // If the table does not have enough columns to fill the view we'll get -1.
  637           // Replace this with the index of the last column.
  638           if (cMax == -1) {
  639               cMax = cm.getColumnCount()-1;
  640           }
  641   
  642           TableColumn draggedColumn = header.getDraggedColumn();
  643           int columnWidth;
  644           Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
  645           TableColumn aColumn;
  646           if (ltr) {
  647               for(int column = cMin; column <= cMax ; column++) {
  648                   aColumn = cm.getColumn(column);
  649                   columnWidth = aColumn.getWidth();
  650                   cellRect.width = columnWidth;
  651                   if (aColumn != draggedColumn) {
  652                       paintCell(g, cellRect, column);
  653                   }
  654                   cellRect.x += columnWidth;
  655               }
  656           } else {
  657               for(int column = cMax; column >= cMin; column--) {
  658                   aColumn = cm.getColumn(column);
  659                   columnWidth = aColumn.getWidth();
  660                   cellRect.width = columnWidth;
  661                   if (aColumn != draggedColumn) {
  662                       paintCell(g, cellRect, column);
  663                   }
  664                   cellRect.x += columnWidth;
  665               }
  666           }
  667   
  668           // Paint the dragged column if we are dragging.
  669           if (draggedColumn != null) {
  670               int draggedColumnIndex = viewIndexForColumn(draggedColumn);
  671               Rectangle draggedCellRect = header.getHeaderRect(draggedColumnIndex);
  672   
  673               // Draw a gray well in place of the moving column.
  674               g.setColor(header.getParent().getBackground());
  675               g.fillRect(draggedCellRect.x, draggedCellRect.y,
  676                                  draggedCellRect.width, draggedCellRect.height);
  677   
  678               draggedCellRect.x += header.getDraggedDistance();
  679   
  680               // Fill the background.
  681               g.setColor(header.getBackground());
  682               g.fillRect(draggedCellRect.x, draggedCellRect.y,
  683                          draggedCellRect.width, draggedCellRect.height);
  684   
  685               paintCell(g, draggedCellRect, draggedColumnIndex);
  686           }
  687   
  688           // Remove all components in the rendererPane.
  689           rendererPane.removeAll();
  690       }
  691   
  692       private Component getHeaderRenderer(int columnIndex) {
  693           TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
  694           TableCellRenderer renderer = aColumn.getHeaderRenderer();
  695           if (renderer == null) {
  696               renderer = header.getDefaultRenderer();
  697           }
  698   
  699           boolean hasFocus = !header.isPaintingForPrint()
  700                              && (columnIndex == getSelectedColumnIndex())
  701                              && header.hasFocus();
  702           return renderer.getTableCellRendererComponent(header.getTable(),
  703                                                   aColumn.getHeaderValue(),
  704                                                   false, hasFocus,
  705                                                   -1, columnIndex);
  706       }
  707   
  708       private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
  709           Component component = getHeaderRenderer(columnIndex);
  710           rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
  711                               cellRect.width, cellRect.height, true);
  712       }
  713   
  714       private int viewIndexForColumn(TableColumn aColumn) {
  715           TableColumnModel cm = header.getColumnModel();
  716           for (int column = 0; column < cm.getColumnCount(); column++) {
  717               if (cm.getColumn(column) == aColumn) {
  718                   return column;
  719               }
  720           }
  721           return -1;
  722       }
  723   
  724   //
  725   // Size Methods
  726   //
  727   
  728       private int getHeaderHeight() {
  729           int height = 0;
  730           boolean accomodatedDefault = false;
  731           TableColumnModel columnModel = header.getColumnModel();
  732           for(int column = 0; column < columnModel.getColumnCount(); column++) {
  733               TableColumn aColumn = columnModel.getColumn(column);
  734               boolean isDefault = (aColumn.getHeaderRenderer() == null);
  735   
  736               if (!isDefault || !accomodatedDefault) {
  737                   Component comp = getHeaderRenderer(column);
  738                   int rendererHeight = comp.getPreferredSize().height;
  739                   height = Math.max(height, rendererHeight);
  740   
  741                   // Configuring the header renderer to calculate its preferred size
  742                   // is expensive. Optimise this by assuming the default renderer
  743                   // always has the same height as the first non-zero height that
  744                   // it returns for a non-null/non-empty value.
  745                   if (isDefault && rendererHeight > 0) {
  746                       Object headerValue = aColumn.getHeaderValue();
  747                       if (headerValue != null) {
  748                           headerValue = headerValue.toString();
  749   
  750                           if (headerValue != null && !headerValue.equals("")) {
  751                               accomodatedDefault = true;
  752                           }
  753                       }
  754                   }
  755               }
  756           }
  757           return height;
  758       }
  759   
  760       private Dimension createHeaderSize(long width) {
  761           // None of the callers include the intercell spacing, do it here.
  762           if (width > Integer.MAX_VALUE) {
  763               width = Integer.MAX_VALUE;
  764           }
  765           return new Dimension((int)width, getHeaderHeight());
  766       }
  767   
  768   
  769       /**
  770        * Return the minimum size of the header. The minimum width is the sum
  771        * of the minimum widths of each column (plus inter-cell spacing).
  772        */
  773       public Dimension getMinimumSize(JComponent c) {
  774           long width = 0;
  775           Enumeration enumeration = header.getColumnModel().getColumns();
  776           while (enumeration.hasMoreElements()) {
  777               TableColumn aColumn = (TableColumn)enumeration.nextElement();
  778               width = width + aColumn.getMinWidth();
  779           }
  780           return createHeaderSize(width);
  781       }
  782   
  783       /**
  784        * Return the preferred size of the header. The preferred height is the
  785        * maximum of the preferred heights of all of the components provided
  786        * by the header renderers. The preferred width is the sum of the
  787        * preferred widths of each column (plus inter-cell spacing).
  788        */
  789       public Dimension getPreferredSize(JComponent c) {
  790           long width = 0;
  791           Enumeration enumeration = header.getColumnModel().getColumns();
  792           while (enumeration.hasMoreElements()) {
  793               TableColumn aColumn = (TableColumn)enumeration.nextElement();
  794               width = width + aColumn.getPreferredWidth();
  795           }
  796           return createHeaderSize(width);
  797       }
  798   
  799       /**
  800        * Return the maximum size of the header. The maximum width is the sum
  801        * of the maximum widths of each column (plus inter-cell spacing).
  802        */
  803       public Dimension getMaximumSize(JComponent c) {
  804           long width = 0;
  805           Enumeration enumeration = header.getColumnModel().getColumns();
  806           while (enumeration.hasMoreElements()) {
  807               TableColumn aColumn = (TableColumn)enumeration.nextElement();
  808               width = width + aColumn.getMaxWidth();
  809           }
  810           return createHeaderSize(width);
  811       }
  812   
  813       private static class Actions extends UIAction {
  814           public static final String TOGGLE_SORT_ORDER =
  815               "toggleSortOrder";
  816           public static final String SELECT_COLUMN_TO_LEFT =
  817               "selectColumnToLeft";
  818           public static final String SELECT_COLUMN_TO_RIGHT =
  819               "selectColumnToRight";
  820           public static final String MOVE_COLUMN_LEFT =
  821               "moveColumnLeft";
  822           public static final String MOVE_COLUMN_RIGHT =
  823               "moveColumnRight";
  824           public static final String RESIZE_LEFT =
  825               "resizeLeft";
  826           public static final String RESIZE_RIGHT =
  827               "resizeRight";
  828           public static final String FOCUS_TABLE =
  829               "focusTable";
  830   
  831           public Actions(String name) {
  832               super(name);
  833           }
  834   
  835           public boolean isEnabled(Object sender) {
  836               if (sender instanceof JTableHeader) {
  837                   JTableHeader th = (JTableHeader)sender;
  838                   TableColumnModel cm = th.getColumnModel();
  839                   if (cm.getColumnCount() <= 0) {
  840                       return false;
  841                   }
  842   
  843                   String key = getName();
  844                   BasicTableHeaderUI ui =
  845                       (BasicTableHeaderUI)BasicLookAndFeel.getUIOfType(th.getUI(),
  846                                                         BasicTableHeaderUI.class);
  847                   if (ui != null) {
  848                       if (key == MOVE_COLUMN_LEFT) {
  849                           return th.getReorderingAllowed()
  850                               && maybeMoveColumn(true, th, ui, false);
  851                       } else if (key == MOVE_COLUMN_RIGHT) {
  852                           return th.getReorderingAllowed()
  853                               && maybeMoveColumn(false, th, ui, false);
  854                       } else if (key == RESIZE_LEFT ||
  855                                  key == RESIZE_RIGHT) {
  856                           return canResize(cm.getColumn(ui.getSelectedColumnIndex()), th);
  857                       } else if (key == FOCUS_TABLE) {
  858                           return (th.getTable() != null);
  859                       }
  860                   }
  861               }
  862               return true;
  863           }
  864   
  865           public void actionPerformed(ActionEvent e) {
  866               JTableHeader th = (JTableHeader)e.getSource();
  867               BasicTableHeaderUI ui =
  868                   (BasicTableHeaderUI)BasicLookAndFeel.
  869                                           getUIOfType(th.getUI(),
  870                                               BasicTableHeaderUI.class);
  871               if (ui == null) {
  872                   return;
  873               }
  874   
  875               String name = getName();
  876               if (TOGGLE_SORT_ORDER == name) {
  877                   JTable table = th.getTable();
  878                   RowSorter sorter = table == null ? null : table.getRowSorter();
  879                   if (sorter != null) {
  880                       int columnIndex = ui.getSelectedColumnIndex();
  881                       columnIndex = table.convertColumnIndexToModel(
  882                                                         columnIndex);
  883                       sorter.toggleSortOrder(columnIndex);
  884                   }
  885               } else if (SELECT_COLUMN_TO_LEFT == name) {
  886                   if (th.getComponentOrientation().isLeftToRight()) {
  887                       ui.selectPreviousColumn(true);
  888                   } else {
  889                       ui.selectNextColumn(true);
  890                   }
  891               } else if (SELECT_COLUMN_TO_RIGHT == name) {
  892                   if (th.getComponentOrientation().isLeftToRight()) {
  893                       ui.selectNextColumn(true);
  894                   } else {
  895                       ui.selectPreviousColumn(true);
  896                   }
  897               } else if (MOVE_COLUMN_LEFT == name) {
  898                   moveColumn(true, th, ui);
  899               } else if (MOVE_COLUMN_RIGHT == name) {
  900                   moveColumn(false, th, ui);
  901               } else if (RESIZE_LEFT == name) {
  902                   resize(true, th, ui);
  903               } else if (RESIZE_RIGHT == name) {
  904                   resize(false, th, ui);
  905               } else if (FOCUS_TABLE == name) {
  906                   JTable table = th.getTable();
  907                   if (table != null) {
  908                       table.requestFocusInWindow();
  909                   }
  910               }
  911           }
  912   
  913           private void moveColumn(boolean leftArrow, JTableHeader th,
  914                                   BasicTableHeaderUI ui) {
  915               maybeMoveColumn(leftArrow, th, ui, true);
  916           }
  917   
  918           private boolean maybeMoveColumn(boolean leftArrow, JTableHeader th,
  919                                           BasicTableHeaderUI ui, boolean doIt) {
  920               int oldIndex = ui.getSelectedColumnIndex();
  921               int newIndex;
  922   
  923               if (th.getComponentOrientation().isLeftToRight()) {
  924                   newIndex = leftArrow ? ui.selectPreviousColumn(doIt)
  925                                        : ui.selectNextColumn(doIt);
  926               } else {
  927                   newIndex = leftArrow ? ui.selectNextColumn(doIt)
  928                                        : ui.selectPreviousColumn(doIt);
  929               }
  930   
  931               if (newIndex != oldIndex) {
  932                   if (doIt) {
  933                       th.getColumnModel().moveColumn(oldIndex, newIndex);
  934                   } else {
  935                       return true; // we'd do the move if asked
  936                   }
  937               }
  938   
  939               return false;
  940           }
  941   
  942           private void resize(boolean leftArrow, JTableHeader th,
  943                               BasicTableHeaderUI ui) {
  944               int columnIndex = ui.getSelectedColumnIndex();
  945               TableColumn resizingColumn =
  946                   th.getColumnModel().getColumn(columnIndex);
  947   
  948               th.setResizingColumn(resizingColumn);
  949               int oldWidth = resizingColumn.getWidth();
  950               int newWidth = oldWidth;
  951   
  952               if (th.getComponentOrientation().isLeftToRight()) {
  953                   newWidth = newWidth + (leftArrow ? -1 : 1);
  954               } else {
  955                   newWidth = newWidth + (leftArrow ? 1 : -1);
  956               }
  957   
  958               ui.changeColumnWidth(resizingColumn, th, oldWidth, newWidth);
  959           }
  960       }
  961   }  // End of Class BasicTableHeaderUI

Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]