mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			567 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			567 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* BasicTableHeaderUI.java --
 | |
|    Copyright (C) 2004 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package javax.swing.plaf.basic;
 | |
| 
 | |
| import java.awt.Component;
 | |
| import java.awt.Cursor;
 | |
| import java.awt.Dimension;
 | |
| import java.awt.Graphics;
 | |
| import java.awt.Rectangle;
 | |
| import java.awt.event.ActionEvent;
 | |
| import java.awt.event.ActionListener;
 | |
| import java.awt.event.MouseEvent;
 | |
| 
 | |
| import javax.swing.CellRendererPane;
 | |
| import javax.swing.JComponent;
 | |
| import javax.swing.LookAndFeel;
 | |
| import javax.swing.Timer;
 | |
| import javax.swing.UIManager;
 | |
| import javax.swing.border.Border;
 | |
| import javax.swing.event.MouseInputListener;
 | |
| import javax.swing.plaf.ComponentUI;
 | |
| import javax.swing.plaf.TableHeaderUI;
 | |
| import javax.swing.table.JTableHeader;
 | |
| import javax.swing.table.TableCellRenderer;
 | |
| import javax.swing.table.TableColumn;
 | |
| import javax.swing.table.TableColumnModel;
 | |
| 
 | |
| /**
 | |
|  * Basic pluggable look and feel interface for JTableHeader.
 | |
|  */
 | |
| public class BasicTableHeaderUI extends TableHeaderUI
 | |
| {
 | |
|   /**
 | |
|    * The width of the space (in both direction) around the column boundary,
 | |
|    * where mouse cursor changes shape into "resize"
 | |
|    */
 | |
|   static int COLUMN_BOUNDARY_TOLERANCE = 3;
 | |
| 
 | |
|   public static ComponentUI createUI(JComponent h)
 | |
|   {
 | |
|     return new BasicTableHeaderUI();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * The table header that is using this interface.
 | |
|    */
 | |
|   protected JTableHeader header;
 | |
| 
 | |
|   /**
 | |
|    * The mouse input listener, responsible for mouse manipulations with
 | |
|    * the table header.
 | |
|    */
 | |
|   protected MouseInputListener mouseInputListener;
 | |
| 
 | |
|   /**
 | |
|    * Paint the header cell.
 | |
|    */
 | |
|   protected CellRendererPane rendererPane;
 | |
| 
 | |
|   /**
 | |
|    * The header cell border.
 | |
|    */
 | |
|   private Border cellBorder;
 | |
| 
 | |
|   /**
 | |
|    * Original mouse cursor prior to resizing.
 | |
|    */
 | |
|   private Cursor originalCursor;
 | |
| 
 | |
|   /**
 | |
|    * If not null, one of the columns is currently being dragged.
 | |
|    */
 | |
|   Rectangle draggingHeaderRect;
 | |
| 
 | |
|   /**
 | |
|    * Handles column movement and rearrangement by mouse. The same instance works
 | |
|    * both as mouse listener and the mouse motion listner.
 | |
|    */
 | |
|   public class MouseInputHandler
 | |
|       implements MouseInputListener
 | |
|   {
 | |
|     /**
 | |
|      * If true, the cursor is being already shown in the alternative "resize"
 | |
|      * shape.
 | |
|      */
 | |
|     boolean showingResizeCursor;
 | |
| 
 | |
|     /**
 | |
|      * The position, from where the cursor is dragged during resizing. Double
 | |
|      * purpose field (absolute value during resizing and relative offset during
 | |
|      * column dragging).
 | |
|      */
 | |
|     int draggingFrom = - 1;
 | |
| 
 | |
|     /**
 | |
|      * The number of the column being dragged.
 | |
|      */
 | |
|     int draggingColumnNumber;
 | |
| 
 | |
|     /**
 | |
|      * The previous preferred width of the column.
 | |
|      */
 | |
|     int prevPrefWidth = - 1;
 | |
| 
 | |
|     /**
 | |
|      * The timer to coalesce column resizing events.
 | |
|      */
 | |
|     Timer timer;
 | |
| 
 | |
|     /**
 | |
|      * Returns without action, part of the MouseInputListener interface.
 | |
|      */
 | |
|     public void mouseClicked(MouseEvent e)
 | |
|     {
 | |
|       // Nothing to do.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * If being in the resizing mode, handle resizing.
 | |
|      */
 | |
|     public void mouseDragged(MouseEvent e)
 | |
|     {
 | |
|       TableColumn resizeIt = header.getResizingColumn();
 | |
|       if (resizeIt != null && header.getResizingAllowed())
 | |
|         {
 | |
|           // The timer is intialised on demand.
 | |
|           if (timer == null)
 | |
|             {
 | |
|               // The purpose of timer is to coalesce events. If the queue
 | |
|               // is free, the repaint event is fired immediately.
 | |
|               timer = new Timer(1, new ActionListener()
 | |
|               {
 | |
|                 public void actionPerformed(ActionEvent e)
 | |
|                 {
 | |
|                   header.getTable().doLayout();
 | |
|                 }
 | |
|               });
 | |
|               timer.setRepeats(false);
 | |
|               timer.setCoalesce(true);
 | |
|             }
 | |
|           resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom);
 | |
|           timer.restart();
 | |
|         }
 | |
|       else if (draggingHeaderRect != null && header.getReorderingAllowed())
 | |
|         {
 | |
|           draggingHeaderRect.x = e.getX() + draggingFrom;
 | |
|           header.repaint();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns without action, part of the MouseInputListener interface.
 | |
|      */
 | |
|     public void mouseEntered(MouseEvent e)
 | |
|     {
 | |
|       // Nothing to do.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Reset drag information of the column resizing.
 | |
|      */
 | |
|     public void mouseExited(MouseEvent e)
 | |
|     {
 | |
|       // Nothing to do.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Change the mouse cursor if the mouse if above the column boundary.
 | |
|      */
 | |
|     public void mouseMoved(MouseEvent e)
 | |
|     {
 | |
|       // When dragging, the functionality is handled by the mouseDragged.
 | |
|       if (e.getButton() == 0 && header.getResizingAllowed())
 | |
|         {
 | |
|           TableColumnModel model = header.getColumnModel();
 | |
|           int n = model.getColumnCount();
 | |
|           if (n < 2)
 | |
|             // It must be at least two columns to have at least one boundary.
 | |
|             // Otherwise, nothing to do.
 | |
|             return;
 | |
| 
 | |
|           boolean onBoundary = false;
 | |
| 
 | |
|           int x = e.getX();
 | |
|           int a = x - COLUMN_BOUNDARY_TOLERANCE;
 | |
|           int b = x + COLUMN_BOUNDARY_TOLERANCE;
 | |
| 
 | |
|           int p = 0;
 | |
| 
 | |
|           Scan: for (int i = 0; i < n - 1; i++)
 | |
|             {
 | |
|               p += model.getColumn(i).getWidth();
 | |
| 
 | |
|               if (p >= a && p <= b)
 | |
|                 {
 | |
|                   TableColumn column = model.getColumn(i);
 | |
|                   onBoundary = true;
 | |
| 
 | |
|                   draggingFrom = x;
 | |
|                   prevPrefWidth = column.getWidth();
 | |
|                   header.setResizingColumn(column);
 | |
|                   break Scan;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|           if (onBoundary != showingResizeCursor)
 | |
|             {
 | |
|               // Change the cursor shape, if needed.
 | |
|               if (onBoundary)
 | |
|                 {
 | |
| 
 | |
|                   originalCursor = header.getCursor();
 | |
|                   if (p < x)
 | |
|                     header.setCursor(Cursor.getPredefinedCursor(
 | |
|                         Cursor.W_RESIZE_CURSOR));
 | |
|                   else
 | |
|                     header.setCursor(Cursor.getPredefinedCursor(
 | |
|                         Cursor.E_RESIZE_CURSOR));
 | |
|                 }
 | |
|               else
 | |
|                 {
 | |
|                   header.setCursor(originalCursor);
 | |
|                   header.setResizingColumn(null);
 | |
|                 }
 | |
| 
 | |
|               showingResizeCursor = onBoundary;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Starts the dragging/resizing procedure.
 | |
|      */
 | |
|     public void mousePressed(MouseEvent e)
 | |
|     {
 | |
|       if (header.getResizingAllowed())
 | |
|         {
 | |
|           TableColumn resizingColumn = header.getResizingColumn();
 | |
|           if (resizingColumn != null)
 | |
|             {
 | |
|               resizingColumn.setPreferredWidth(resizingColumn.getWidth());
 | |
|               return;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       if (header.getReorderingAllowed())
 | |
|         {
 | |
|           TableColumnModel model = header.getColumnModel();
 | |
|           int n = model.getColumnCount();
 | |
|           if (n < 2)
 | |
|             // It must be at least two columns to change the column location.
 | |
|             return;
 | |
| 
 | |
|           boolean onBoundary = false;
 | |
| 
 | |
|           int x = e.getX();
 | |
|           int p = 0;
 | |
|           int col = - 1;
 | |
| 
 | |
|           Scan: for (int i = 0; i < n; i++)
 | |
|             {
 | |
|               p += model.getColumn(i).getWidth();
 | |
|               if (p > x)
 | |
|                 {
 | |
|                   col = i;
 | |
|                   break Scan;
 | |
|                 }
 | |
|             }
 | |
|           if (col < 0)
 | |
|             return;
 | |
| 
 | |
|           TableColumn dragIt = model.getColumn(col);
 | |
|           header.setDraggedColumn(dragIt);
 | |
| 
 | |
|           draggingFrom = (p - dragIt.getWidth()) - x;
 | |
|           draggingHeaderRect = new Rectangle(header.getHeaderRect(col));
 | |
|           draggingColumnNumber = col;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set all column preferred width to the current width to prevend abrupt
 | |
|      * width changes during the next resize.
 | |
|      */
 | |
|     public void mouseReleased(MouseEvent e)
 | |
|     {
 | |
|       if (header.getResizingColumn() != null && header.getResizingAllowed())
 | |
|         endResizing();
 | |
|       if (header.getDraggedColumn() != null &&  header.getReorderingAllowed())
 | |
|         endDragging(e);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Stop resizing session.
 | |
|      */
 | |
|     void endResizing()
 | |
|     {
 | |
|       TableColumnModel model = header.getColumnModel();
 | |
|       int n = model.getColumnCount();
 | |
|       if (n > 2)
 | |
|         {
 | |
|           TableColumn c;
 | |
|           for (int i = 0; i < n; i++)
 | |
|             {
 | |
|               c = model.getColumn(i);
 | |
|               c.setPreferredWidth(c.getWidth());
 | |
|             }
 | |
|         }
 | |
|       header.setResizingColumn(null);
 | |
|       showingResizeCursor = false;
 | |
|       if (timer != null)
 | |
|         timer.stop();
 | |
|       header.setCursor(originalCursor);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Stop the dragging session.
 | |
|      *
 | |
|      * @param e the "mouse release" mouse event, needed to determing the final
 | |
|      *          location for the dragged column.
 | |
|      */
 | |
|     void endDragging(MouseEvent e)
 | |
|     {
 | |
|       header.setDraggedColumn(null);
 | |
|       draggingHeaderRect = null;
 | |
| 
 | |
|       TableColumnModel model = header.getColumnModel();
 | |
| 
 | |
|       // Find where have we dragged the column.
 | |
|       int x = e.getX();
 | |
|       int p = 0;
 | |
| 
 | |
|       int col = model.getColumnCount() - 1;
 | |
|       int n = model.getColumnCount();
 | |
| 
 | |
|       // This loop does not find the column if the mouse if out of the
 | |
|       // right boundary of the table header. Then we make this column the
 | |
|       // rightmost column.
 | |
|       Scan: for (int i = 0; i < n; i++)
 | |
|         {
 | |
|           p += model.getColumn(i).getWidth();
 | |
|           if (p > x)
 | |
|             {
 | |
|               col = i;
 | |
|               break Scan;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       header.getTable().moveColumn(draggingColumnNumber, col);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Create and return the mouse input listener.
 | |
|    *
 | |
|    * @return the mouse listener ({@link MouseInputHandler}, if not overridden.
 | |
|    */
 | |
|   protected MouseInputListener createMouseInputListener()
 | |
|   {
 | |
|     return new MouseInputHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Construct a new BasicTableHeaderUI, create mouse listeners.
 | |
|    */
 | |
|   public BasicTableHeaderUI()
 | |
|   {
 | |
|     mouseInputListener = createMouseInputListener();
 | |
|   }
 | |
| 
 | |
|   protected void installDefaults()
 | |
|   {
 | |
|     LookAndFeel.installColorsAndFont(header, "TableHeader.background",
 | |
|                                      "TableHeader.foreground",
 | |
|                                      "TableHeader.font");
 | |
|     cellBorder = UIManager.getBorder("TableHeader.cellBorder");
 | |
|   }
 | |
| 
 | |
|   protected void installKeyboardActions()
 | |
|   {
 | |
|     // AFAICS, the RI does nothing here.
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Add the mouse listener and the mouse motion listener to the table
 | |
|    * header. The listeners support table column resizing and rearrangement
 | |
|    * by mouse.
 | |
|    */
 | |
|   protected void installListeners()
 | |
|   {
 | |
|     header.addMouseListener(mouseInputListener);
 | |
|     header.addMouseMotionListener(mouseInputListener);
 | |
|   }
 | |
| 
 | |
|   public void installUI(JComponent c)
 | |
|   {
 | |
|     header = (JTableHeader) c;
 | |
|     rendererPane = new CellRendererPane();
 | |
|     installDefaults();
 | |
|     installKeyboardActions();
 | |
|     installListeners();
 | |
|   }
 | |
| 
 | |
|   protected void uninstallDefaults()
 | |
|   {
 | |
|     header.setBackground(null);
 | |
|     header.setForeground(null);
 | |
|     header.setFont(null);
 | |
|   }
 | |
| 
 | |
|   protected void uninstallKeyboardActions()
 | |
|   {
 | |
|     // AFAICS, the RI does nothing here.
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Remove the previously installed listeners.
 | |
|    */
 | |
|   protected void uninstallListeners()
 | |
|   {
 | |
|     header.removeMouseListener(mouseInputListener);
 | |
|     header.removeMouseMotionListener(mouseInputListener);
 | |
|   }
 | |
| 
 | |
|   public void uninstallUI(JComponent c)
 | |
|   {
 | |
|     uninstallListeners();
 | |
|     uninstallKeyboardActions();
 | |
|     uninstallDefaults();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Repaint the table header.
 | |
|    */
 | |
|   public void paint(Graphics gfx, JComponent c)
 | |
|   {
 | |
|     TableColumnModel cmod = header.getColumnModel();
 | |
|     int ncols = cmod.getColumnCount();
 | |
|     if (ncols == 0)
 | |
|       return;
 | |
| 
 | |
|     Rectangle clip = gfx.getClipBounds();
 | |
|     TableCellRenderer defaultRend = header.getDefaultRenderer();
 | |
| 
 | |
|     for (int i = 0; i < ncols; ++i)
 | |
|       {
 | |
|         Rectangle bounds = header.getHeaderRect(i);
 | |
|         if (bounds.intersects(clip))
 | |
|           {
 | |
|             Rectangle oldClip = gfx.getClipBounds();
 | |
|             TableColumn col = cmod.getColumn(i);
 | |
|             TableCellRenderer rend = col.getHeaderRenderer();
 | |
|             if (rend == null)
 | |
|               rend = defaultRend;
 | |
|             Object val = col.getHeaderValue();
 | |
|             Component comp = rend.getTableCellRendererComponent(header.getTable(),
 | |
|                                                                 val,
 | |
|                                                                 false, // isSelected
 | |
|                                                                 false, // isFocused
 | |
|                                                                 -1, i);
 | |
|             // FIXME: The following settings should be performed in
 | |
|             // rend.getTableCellRendererComponent().
 | |
|             comp.setFont(header.getFont());
 | |
|             comp.setBackground(header.getBackground());
 | |
|             comp.setForeground(header.getForeground());
 | |
|             if (comp instanceof JComponent)
 | |
|               ((JComponent) comp).setBorder(cellBorder);
 | |
|             rendererPane.paintComponent(gfx, comp, header, bounds.x, bounds.y,
 | |
|                                         bounds.width, bounds.height);
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     // This displays a running rectangle that is much simplier than the total
 | |
|     // animation, as it is seen in Sun's application.
 | |
|     // TODO animate the collumn dragging like in Sun's jre.
 | |
|     if (draggingHeaderRect != null)
 | |
|       {
 | |
|         gfx.setColor(header.getForeground());
 | |
|         gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y + 2,
 | |
|             draggingHeaderRect.width - 1, draggingHeaderRect.height - 6);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the preferred header size.
 | |
|    *
 | |
|    * @param ignored unused
 | |
|    *
 | |
|    * @return the preferred size of the associated header.
 | |
|    */
 | |
|   public Dimension getPreferredSize(JComponent ignored)
 | |
|   {
 | |
|     TableColumnModel cmod = header.getColumnModel();
 | |
|     TableCellRenderer defaultRend = header.getDefaultRenderer();
 | |
|     int ncols = cmod.getColumnCount();
 | |
|     Dimension ret = new Dimension(0, 0);
 | |
|     int spacing = 0;
 | |
| 
 | |
|     if (header.getTable() != null
 | |
|         && header.getTable().getIntercellSpacing() != null)
 | |
|       spacing = header.getTable().getIntercellSpacing().width;
 | |
| 
 | |
|     for (int i = 0; i < ncols; ++i)
 | |
|       {
 | |
|         TableColumn col = cmod.getColumn(i);
 | |
|         TableCellRenderer rend = col.getHeaderRenderer();
 | |
|         if (rend == null)
 | |
|           rend = defaultRend;
 | |
|         Object val = col.getHeaderValue();
 | |
|         Component comp = rend.getTableCellRendererComponent(header.getTable(),
 | |
|                                                             val,
 | |
|                                                             false, // isSelected
 | |
|                                                             false, // isFocused
 | |
|                                                             -1, i);
 | |
|         comp.setFont(header.getFont());
 | |
|         comp.setBackground(header.getBackground());
 | |
|         comp.setForeground(header.getForeground());
 | |
|         if (comp instanceof JComponent)
 | |
|           ((JComponent) comp).setBorder(cellBorder);
 | |
| 
 | |
|         Dimension d = comp.getPreferredSize();
 | |
|         ret.width += spacing;
 | |
|         ret.height = Math.max(d.height, ret.height);
 | |
|       }
 | |
|     ret.width = cmod.getTotalColumnWidth();
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
| 
 | |
| }
 |