mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1422 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1422 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* BasicListUI.java --
 | |
|    Copyright (C) 2002, 2004, 2005, 2006 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.Dimension;
 | |
| import java.awt.Graphics;
 | |
| import java.awt.Insets;
 | |
| import java.awt.Point;
 | |
| import java.awt.Rectangle;
 | |
| import java.awt.event.ActionEvent;
 | |
| import java.awt.event.ActionListener;
 | |
| import java.awt.event.FocusEvent;
 | |
| import java.awt.event.FocusListener;
 | |
| import java.awt.event.MouseEvent;
 | |
| import java.beans.PropertyChangeEvent;
 | |
| import java.beans.PropertyChangeListener;
 | |
| 
 | |
| import javax.swing.AbstractAction;
 | |
| import javax.swing.ActionMap;
 | |
| import javax.swing.CellRendererPane;
 | |
| import javax.swing.DefaultListSelectionModel;
 | |
| import javax.swing.InputMap;
 | |
| import javax.swing.JComponent;
 | |
| import javax.swing.JList;
 | |
| import javax.swing.ListCellRenderer;
 | |
| import javax.swing.ListModel;
 | |
| import javax.swing.ListSelectionModel;
 | |
| import javax.swing.LookAndFeel;
 | |
| import javax.swing.SwingUtilities;
 | |
| import javax.swing.TransferHandler;
 | |
| import javax.swing.UIDefaults;
 | |
| import javax.swing.UIManager;
 | |
| import javax.swing.event.ListDataEvent;
 | |
| import javax.swing.event.ListDataListener;
 | |
| import javax.swing.event.ListSelectionEvent;
 | |
| import javax.swing.event.ListSelectionListener;
 | |
| import javax.swing.event.MouseInputListener;
 | |
| import javax.swing.plaf.ActionMapUIResource;
 | |
| import javax.swing.plaf.ComponentUI;
 | |
| import javax.swing.plaf.ListUI;
 | |
| import javax.swing.plaf.UIResource;
 | |
| 
 | |
| /**
 | |
|  * The Basic Look and Feel UI delegate for the
 | |
|  * JList.
 | |
|  */
 | |
| public class BasicListUI extends ListUI
 | |
| {
 | |
| 
 | |
|   /**
 | |
|    * A helper class which listens for {@link FocusEvent}s
 | |
|    * from the JList.
 | |
|    */
 | |
|   public class FocusHandler implements FocusListener
 | |
|   {
 | |
|     /**
 | |
|      * Called when the JList acquires focus.
 | |
|      *
 | |
|      * @param e The FocusEvent representing focus acquisition
 | |
|      */
 | |
|     public void focusGained(FocusEvent e)
 | |
|     {
 | |
|       repaintCellFocus();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when the JList loses focus.
 | |
|      *
 | |
|      * @param e The FocusEvent representing focus loss
 | |
|      */
 | |
|     public void focusLost(FocusEvent e)
 | |
|     {
 | |
|       repaintCellFocus();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Helper method to repaint the focused cell's
 | |
|      * lost or acquired focus state.
 | |
|      */
 | |
|     protected void repaintCellFocus()
 | |
|     {
 | |
|       // TODO: Implement this properly.
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A helper class which listens for {@link ListDataEvent}s generated by
 | |
|    * the {@link JList}'s {@link ListModel}.
 | |
|    *
 | |
|    * @see javax.swing.JList#getModel()
 | |
|    */
 | |
|   public class ListDataHandler implements ListDataListener
 | |
|   {
 | |
|     /**
 | |
|      * Called when a general change has happened in the model which cannot
 | |
|      * be represented in terms of a simple addition or deletion.
 | |
|      *
 | |
|      * @param e The event representing the change
 | |
|      */
 | |
|     public void contentsChanged(ListDataEvent e)
 | |
|     {
 | |
|       updateLayoutStateNeeded |= modelChanged;
 | |
|       list.revalidate();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when an interval of objects has been added to the model.
 | |
|      *
 | |
|      * @param e The event representing the addition
 | |
|      */
 | |
|     public void intervalAdded(ListDataEvent e)
 | |
|     {
 | |
|       updateLayoutStateNeeded |= modelChanged;
 | |
|       list.revalidate();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when an inteval of objects has been removed from the model.
 | |
|      *
 | |
|      * @param e The event representing the removal
 | |
|      */
 | |
|     public void intervalRemoved(ListDataEvent e)
 | |
|     {
 | |
|       updateLayoutStateNeeded |= modelChanged;
 | |
|       list.revalidate();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A helper class which listens for {@link ListSelectionEvent}s
 | |
|    * from the {@link JList}'s {@link ListSelectionModel}.
 | |
|    */
 | |
|   public class ListSelectionHandler implements ListSelectionListener
 | |
|   {
 | |
|     /**
 | |
|      * Called when the list selection changes.
 | |
|      *
 | |
|      * @param e The event representing the change
 | |
|      */
 | |
|     public void valueChanged(ListSelectionEvent e)
 | |
|     {
 | |
|       int index1 = e.getFirstIndex();
 | |
|       int index2 = e.getLastIndex();
 | |
|       Rectangle damaged = getCellBounds(list, index1, index2);
 | |
|       if (damaged != null)
 | |
|         list.repaint(damaged);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This class is used to mimmic the behaviour of the JDK when registering
 | |
|    * keyboard actions.  It is the same as the private class used in JComponent
 | |
|    * for the same reason.  This class receives an action event and dispatches
 | |
|    * it to the true receiver after altering the actionCommand property of the
 | |
|    * event.
 | |
|    */
 | |
|   private static class ActionListenerProxy
 | |
|     extends AbstractAction
 | |
|   {
 | |
|     ActionListener target;
 | |
|     String bindingCommandName;
 | |
| 
 | |
|     public ActionListenerProxy(ActionListener li,
 | |
|                                String cmd)
 | |
|     {
 | |
|       target = li;
 | |
|       bindingCommandName = cmd;
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent e)
 | |
|     {
 | |
|       ActionEvent derivedEvent = new ActionEvent(e.getSource(),
 | |
|                                                  e.getID(),
 | |
|                                                  bindingCommandName,
 | |
|                                                  e.getModifiers());
 | |
|       target.actionPerformed(derivedEvent);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Implements the action for the JList's keyboard commands.
 | |
|    */
 | |
|   private class ListAction
 | |
|     extends AbstractAction
 | |
|   {
 | |
|     // TODO: Maybe make a couple of classes out of this bulk Action.
 | |
|     // Form logical groups of Actions when doing this.
 | |
| 
 | |
|     /**
 | |
|      * Creates a new ListAction for the specified command.
 | |
|      *
 | |
|      * @param cmd the actionCommand to set
 | |
|      */
 | |
|     ListAction(String cmd)
 | |
|     {
 | |
|       putValue(ACTION_COMMAND_KEY, cmd);
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent e)
 | |
|     {
 | |
|       int lead = list.getLeadSelectionIndex();
 | |
|       int max = list.getModel().getSize() - 1;
 | |
|       DefaultListSelectionModel selModel
 | |
|           = (DefaultListSelectionModel) list.getSelectionModel();
 | |
|       String command = e.getActionCommand();
 | |
|       // Do nothing if list is empty
 | |
|       if (max == -1)
 | |
|         return;
 | |
| 
 | |
|       if (command.equals("selectNextRow"))
 | |
|         {
 | |
|           selectNextIndex();
 | |
|         }
 | |
|       else if (command.equals("selectPreviousRow"))
 | |
|         {
 | |
|           selectPreviousIndex();
 | |
|         }
 | |
|       else if (command.equals("clearSelection"))
 | |
|         {
 | |
|           list.clearSelection();
 | |
|         }
 | |
|       else if (command.equals("selectAll"))
 | |
|         {
 | |
|           list.setSelectionInterval(0, max);
 | |
|           // this next line is to restore the lead selection index to the old
 | |
|           // position, because select-all should not change the lead index
 | |
|           list.addSelectionInterval(lead, lead);
 | |
|         }
 | |
|       else if (command.equals("selectLastRow"))
 | |
|         {
 | |
|           list.setSelectedIndex(list.getModel().getSize() - 1);
 | |
|         }
 | |
|       else if (command.equals("selectLastRowChangeLead"))
 | |
|         {
 | |
|           selModel.moveLeadSelectionIndex(list.getModel().getSize() - 1);
 | |
|         }
 | |
|       else if (command.equals("scrollDownExtendSelection"))
 | |
|         {
 | |
|           int target;
 | |
|           if (lead == list.getLastVisibleIndex())
 | |
|             {
 | |
|               target = Math.min(max, lead + (list.getLastVisibleIndex()
 | |
|                   - list.getFirstVisibleIndex() + 1));
 | |
|             }
 | |
|           else
 | |
|             target = list.getLastVisibleIndex();
 | |
|           selModel.setLeadSelectionIndex(target);
 | |
|         }
 | |
|       else if (command.equals("scrollDownChangeLead"))
 | |
|         {
 | |
|           int target;
 | |
|           if (lead == list.getLastVisibleIndex())
 | |
|             {
 | |
|               target = Math.min(max, lead + (list.getLastVisibleIndex()
 | |
|                   - list.getFirstVisibleIndex() + 1));
 | |
|             }
 | |
|           else
 | |
|             target = list.getLastVisibleIndex();
 | |
|           selModel.moveLeadSelectionIndex(target);
 | |
|         }
 | |
|       else if (command.equals("scrollUpExtendSelection"))
 | |
|         {
 | |
|           int target;
 | |
|           if (lead == list.getFirstVisibleIndex())
 | |
|             {
 | |
|               target = Math.max(0, lead - (list.getLastVisibleIndex()
 | |
|                   - list.getFirstVisibleIndex() + 1));
 | |
|             }
 | |
|           else
 | |
|             target = list.getFirstVisibleIndex();
 | |
|           selModel.setLeadSelectionIndex(target);
 | |
|         }
 | |
|       else if (command.equals("scrollUpChangeLead"))
 | |
|         {
 | |
|           int target;
 | |
|           if (lead == list.getFirstVisibleIndex())
 | |
|             {
 | |
|               target = Math.max(0, lead - (list.getLastVisibleIndex()
 | |
|                   - list.getFirstVisibleIndex() + 1));
 | |
|             }
 | |
|           else
 | |
|             target = list.getFirstVisibleIndex();
 | |
|           selModel.moveLeadSelectionIndex(target);
 | |
|         }
 | |
|       else if (command.equals("selectNextRowExtendSelection"))
 | |
|         {
 | |
|           selModel.setLeadSelectionIndex(Math.min(lead + 1, max));
 | |
|         }
 | |
|       else if (command.equals("selectFirstRow"))
 | |
|         {
 | |
|           list.setSelectedIndex(0);
 | |
|         }
 | |
|       else if (command.equals("selectFirstRowChangeLead"))
 | |
|         {
 | |
|           selModel.moveLeadSelectionIndex(0);
 | |
|         }
 | |
|       else if (command.equals("selectFirstRowExtendSelection"))
 | |
|         {
 | |
|           selModel.setLeadSelectionIndex(0);
 | |
|         }
 | |
|       else if (command.equals("selectPreviousRowExtendSelection"))
 | |
|         {
 | |
|           selModel.setLeadSelectionIndex(Math.max(0, lead - 1));
 | |
|         }
 | |
|       else if (command.equals("scrollUp"))
 | |
|         {
 | |
|           int target;
 | |
|           if (lead == list.getFirstVisibleIndex())
 | |
|             {
 | |
|               target = Math.max(0, lead - (list.getLastVisibleIndex()
 | |
|                   - list.getFirstVisibleIndex() + 1));
 | |
|             }
 | |
|           else
 | |
|             target = list.getFirstVisibleIndex();
 | |
|           list.setSelectedIndex(target);
 | |
|         }
 | |
|       else if (command.equals("selectLastRowExtendSelection"))
 | |
|         {
 | |
|           selModel.setLeadSelectionIndex(list.getModel().getSize() - 1);
 | |
|         }
 | |
|       else if (command.equals("scrollDown"))
 | |
|         {
 | |
|           int target;
 | |
|           if (lead == list.getLastVisibleIndex())
 | |
|             {
 | |
|               target = Math.min(max, lead + (list.getLastVisibleIndex()
 | |
|                   - list.getFirstVisibleIndex() + 1));
 | |
|             }
 | |
|           else
 | |
|             target = list.getLastVisibleIndex();
 | |
|           list.setSelectedIndex(target);
 | |
|         }
 | |
|       else if (command.equals("selectNextRowChangeLead"))
 | |
|           {
 | |
|             if (selModel.getSelectionMode() != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | |
|               selectNextIndex();
 | |
|             else
 | |
|               {
 | |
|                 selModel.moveLeadSelectionIndex(Math.min(max, lead + 1));
 | |
|               }
 | |
|           }
 | |
|       else if (command.equals("selectPreviousRowChangeLead"))
 | |
|         {
 | |
|           if (selModel.getSelectionMode() != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | |
|             selectPreviousIndex();
 | |
|           else
 | |
|             {
 | |
|               selModel.moveLeadSelectionIndex(Math.max(0, lead - 1));
 | |
|             }
 | |
|         }
 | |
|       else if (command.equals("addToSelection"))
 | |
|         {
 | |
|           list.addSelectionInterval(lead, lead);
 | |
|         }
 | |
|       else if (command.equals("extendTo"))
 | |
|         {
 | |
|           selModel.setSelectionInterval(selModel.getAnchorSelectionIndex(),
 | |
|                                         lead);
 | |
|         }
 | |
|       else if (command.equals("toggleAndAnchor"))
 | |
|         {
 | |
|           if (!list.isSelectedIndex(lead))
 | |
|             list.addSelectionInterval(lead, lead);
 | |
|           else
 | |
|             list.removeSelectionInterval(lead, lead);
 | |
|           selModel.setAnchorSelectionIndex(lead);
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           // DEBUG: uncomment the following line to print out
 | |
|           // key bindings that aren't implemented yet
 | |
| 
 | |
|           // System.out.println ("not implemented: "+e.getActionCommand());
 | |
|         }
 | |
| 
 | |
|       list.ensureIndexIsVisible(list.getLeadSelectionIndex());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A helper class which listens for {@link MouseEvent}s
 | |
|    * from the {@link JList}.
 | |
|    */
 | |
|   public class MouseInputHandler implements MouseInputListener
 | |
|   {
 | |
|     /**
 | |
|      * Called when a mouse button press/release cycle completes
 | |
|      * on the {@link JList}
 | |
|      *
 | |
|      * @param event The event representing the mouse click
 | |
|      */
 | |
|     public void mouseClicked(MouseEvent event)
 | |
|     {
 | |
|       Point click = event.getPoint();
 | |
|       int index = locationToIndex(list, click);
 | |
|       if (index == -1)
 | |
|         return;
 | |
|       if (event.isShiftDown())
 | |
|         {
 | |
|           if (list.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION)
 | |
|             list.setSelectedIndex(index);
 | |
|           else if (list.getSelectionMode() ==
 | |
|                    ListSelectionModel.SINGLE_INTERVAL_SELECTION)
 | |
|             // COMPAT: the IBM VM is compatible with the following line of code.
 | |
|             // However, compliance with Sun's VM would correspond to replacing
 | |
|             // getAnchorSelectionIndex() with getLeadSelectionIndex().This is
 | |
|             // both unnatural and contradictory to the way they handle other
 | |
|             // similar UI interactions.
 | |
|             list.setSelectionInterval(list.getAnchorSelectionIndex(), index);
 | |
|           else
 | |
|             // COMPAT: both Sun and IBM are compatible instead with:
 | |
|             // list.setSelectionInterval
 | |
|             //     (list.getLeadSelectionIndex(),index);
 | |
|             // Note that for IBM this is contradictory to what they did in
 | |
|             // the above situation for SINGLE_INTERVAL_SELECTION.
 | |
|             // The most natural thing to do is the following:
 | |
|             if (list.isSelectedIndex(list.getAnchorSelectionIndex()))
 | |
|               list.getSelectionModel().setLeadSelectionIndex(index);
 | |
|             else
 | |
|               list.addSelectionInterval(list.getAnchorSelectionIndex(), index);
 | |
|         }
 | |
|       else if (event.isControlDown())
 | |
|         {
 | |
|           if (list.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION)
 | |
|             list.setSelectedIndex(index);
 | |
|           else if (list.isSelectedIndex(index))
 | |
|             list.removeSelectionInterval(index, index);
 | |
|           else
 | |
|             list.addSelectionInterval(index, index);
 | |
|         }
 | |
|       else
 | |
|         list.setSelectedIndex(index);
 | |
| 
 | |
|       list.ensureIndexIsVisible(list.getLeadSelectionIndex());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when a mouse button is pressed down on the
 | |
|      * {@link JList}.
 | |
|      *
 | |
|      * @param event The event representing the mouse press
 | |
|      */
 | |
|     public void mousePressed(MouseEvent event)
 | |
|     {
 | |
|       // We need to explicitly request focus.
 | |
|       list.requestFocusInWindow();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when a mouse button is released on
 | |
|      * the {@link JList}
 | |
|      *
 | |
|      * @param event The event representing the mouse press
 | |
|      */
 | |
|     public void mouseReleased(MouseEvent event)
 | |
|     {
 | |
|       // TODO: What should be done here, if anything?
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when the mouse pointer enters the area bounded
 | |
|      * by the {@link JList}
 | |
|      *
 | |
|      * @param event The event representing the mouse entry
 | |
|      */
 | |
|     public void mouseEntered(MouseEvent event)
 | |
|     {
 | |
|       // TODO: What should be done here, if anything?
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when the mouse pointer leaves the area bounded
 | |
|      * by the {@link JList}
 | |
|      *
 | |
|      * @param event The event representing the mouse exit
 | |
|      */
 | |
|     public void mouseExited(MouseEvent event)
 | |
|     {
 | |
|       // TODO: What should be done here, if anything?
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when the mouse pointer moves over the area bounded
 | |
|      * by the {@link JList} while a button is held down.
 | |
|      *
 | |
|      * @param event The event representing the mouse drag
 | |
|      */
 | |
|     public void mouseDragged(MouseEvent event)
 | |
|     {
 | |
|       Point click = event.getPoint();
 | |
|       int index = locationToIndex(list, click);
 | |
|       if (index == -1)
 | |
|         return;
 | |
|       if (!event.isShiftDown() && !event.isControlDown())
 | |
|         list.setSelectedIndex(index);
 | |
| 
 | |
|       list.ensureIndexIsVisible(list.getLeadSelectionIndex());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Called when the mouse pointer moves over the area bounded
 | |
|      * by the {@link JList}.
 | |
|      *
 | |
|      * @param event The event representing the mouse move
 | |
|      */
 | |
|     public void mouseMoved(MouseEvent event)
 | |
|     {
 | |
|       // TODO: What should be done here, if anything?
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Helper class which listens to {@link PropertyChangeEvent}s
 | |
|    * from the {@link JList}.
 | |
|    */
 | |
|   public class PropertyChangeHandler implements PropertyChangeListener
 | |
|   {
 | |
|     /**
 | |
|      * Called when the {@link JList} changes one of its bound properties.
 | |
|      *
 | |
|      * @param e The event representing the property change
 | |
|      */
 | |
|     public void propertyChange(PropertyChangeEvent e)
 | |
|     {
 | |
|       if (e.getPropertyName().equals("model"))
 | |
|         {
 | |
|           if (e.getOldValue() != null && e.getOldValue() instanceof ListModel)
 | |
|             {
 | |
|               ListModel oldModel = (ListModel) e.getOldValue();
 | |
|               oldModel.removeListDataListener(listDataListener);
 | |
|             }
 | |
|           if (e.getNewValue() != null && e.getNewValue() instanceof ListModel)
 | |
|             {
 | |
|               ListModel newModel = (ListModel) e.getNewValue();
 | |
|               newModel.addListDataListener(BasicListUI.this.listDataListener);
 | |
|             }
 | |
| 
 | |
|           updateLayoutStateNeeded |= modelChanged;
 | |
|         }
 | |
|       else if (e.getPropertyName().equals("selectionModel"))
 | |
|         updateLayoutStateNeeded |= selectionModelChanged;
 | |
|       else if (e.getPropertyName().equals("font"))
 | |
|         updateLayoutStateNeeded |= fontChanged;
 | |
|       else if (e.getPropertyName().equals("fixedCellWidth"))
 | |
|         updateLayoutStateNeeded |= fixedCellWidthChanged;
 | |
|       else if (e.getPropertyName().equals("fixedCellHeight"))
 | |
|         updateLayoutStateNeeded |= fixedCellHeightChanged;
 | |
|       else if (e.getPropertyName().equals("prototypeCellValue"))
 | |
|         updateLayoutStateNeeded |= prototypeCellValueChanged;
 | |
|       else if (e.getPropertyName().equals("cellRenderer"))
 | |
|         updateLayoutStateNeeded |= cellRendererChanged;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the model has changed.
 | |
|    */
 | |
|   protected static final int modelChanged = 1;
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the selection model has changed.
 | |
|    */
 | |
|   protected static final int selectionModelChanged = 2;
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the font has changed.
 | |
|    */
 | |
|   protected static final int fontChanged = 4;
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the fixedCellWidth has changed.
 | |
|    */
 | |
|   protected static final int fixedCellWidthChanged = 8;
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the fixedCellHeight has changed.
 | |
|    */
 | |
|   protected static final int fixedCellHeightChanged = 16;
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the prototypeCellValue has changed.
 | |
|    */
 | |
|   protected static final int prototypeCellValueChanged = 32;
 | |
| 
 | |
|   /**
 | |
|    * A constant to indicate that the cellRenderer has changed.
 | |
|    */
 | |
|   protected static final int cellRendererChanged = 64;
 | |
| 
 | |
|   /**
 | |
|    * Creates a new BasicListUI for the component.
 | |
|    *
 | |
|    * @param c The component to create a UI for
 | |
|    *
 | |
|    * @return A new UI
 | |
|    */
 | |
|   public static ComponentUI createUI(final JComponent c)
 | |
|   {
 | |
|     return new BasicListUI();
 | |
|   }
 | |
| 
 | |
|   /** The current focus listener. */
 | |
|   protected FocusListener focusListener;
 | |
| 
 | |
|   /** The data listener listening to the model. */
 | |
|   protected ListDataListener listDataListener;
 | |
| 
 | |
|   /** The selection listener listening to the selection model. */
 | |
|   protected ListSelectionListener listSelectionListener;
 | |
| 
 | |
|   /** The mouse listener listening to the list. */
 | |
|   protected MouseInputListener mouseInputListener;
 | |
| 
 | |
|   /** The property change listener listening to the list. */
 | |
|   protected PropertyChangeListener propertyChangeListener;
 | |
| 
 | |
|   /** Saved reference to the list this UI was created for. */
 | |
|   protected JList list;
 | |
| 
 | |
|   /**
 | |
|    * The height of a single cell in the list. This field is used when the
 | |
|    * fixedCellHeight property of the list is set. Otherwise this field is
 | |
|    * set to <code>-1</code> and {@link #cellHeights} is used instead.
 | |
|    */
 | |
|   protected int cellHeight;
 | |
| 
 | |
|   /** The width of a single cell in the list. */
 | |
|   protected int cellWidth;
 | |
| 
 | |
|   /**
 | |
|    * An array of varying heights of cells in the list, in cases where each
 | |
|    * cell might have a different height. This field is used when the
 | |
|    * <code>fixedCellHeight</code> property of the list is not set. Otherwise
 | |
|    * this field is <code>null</code> and {@link #cellHeight} is used.
 | |
|    */
 | |
|   protected int[] cellHeights;
 | |
| 
 | |
|   /**
 | |
|    * A bitmask that indicates which properties of the JList have changed.
 | |
|    * When nonzero, indicates that the UI class is out of
 | |
|    * date with respect to the underlying list, and must recalculate the
 | |
|    * list layout before painting or performing size calculations.
 | |
|    *
 | |
|    * @see #modelChanged
 | |
|    * @see #selectionModelChanged
 | |
|    * @see #fontChanged
 | |
|    * @see #fixedCellWidthChanged
 | |
|    * @see #fixedCellHeightChanged
 | |
|    * @see #prototypeCellValueChanged
 | |
|    * @see #cellRendererChanged
 | |
|    */
 | |
|   protected int updateLayoutStateNeeded;
 | |
| 
 | |
|   /**
 | |
|    * The {@link CellRendererPane} that is used for painting.
 | |
|    */
 | |
|   protected CellRendererPane rendererPane;
 | |
| 
 | |
|   /** The action bound to KeyStrokes. */
 | |
|   ListAction action;
 | |
| 
 | |
|   /**
 | |
|    * Calculate the height of a particular row. If there is a fixed {@link
 | |
|    * #cellHeight}, return it; otherwise return the specific row height
 | |
|    * requested from the {@link #cellHeights} array. If the requested row
 | |
|    * is invalid, return <code>-1</code>.
 | |
|    *
 | |
|    * @param row The row to get the height of
 | |
|    *
 | |
|    * @return The height, in pixels, of the specified row
 | |
|    */
 | |
|   protected int getRowHeight(int row)
 | |
|   {
 | |
|     int height;
 | |
|     if (cellHeights == null)
 | |
|       height = cellHeight;
 | |
|     else
 | |
|       {
 | |
|         if (row < 0 || row >= cellHeights.length)
 | |
|           height = -1;
 | |
|         else
 | |
|           height = cellHeights[row];
 | |
|       }
 | |
|     return height;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Calculate the bounds of a particular cell, considering the upper left
 | |
|    * corner of the list as the origin position <code>(0,0)</code>.
 | |
|    *
 | |
|    * @param l Ignored; calculates over <code>this.list</code>
 | |
|    * @param index1 The first row to include in the bounds
 | |
|    * @param index2 The last row to incude in the bounds
 | |
|    *
 | |
|    * @return A rectangle encompassing the range of rows between
 | |
|    * <code>index1</code> and <code>index2</code> inclusive, or null
 | |
|    * such a rectangle couldn't be calculated for the given indexes.
 | |
|    */
 | |
|   public Rectangle getCellBounds(JList l, int index1, int index2)
 | |
|   {
 | |
|     maybeUpdateLayoutState();
 | |
| 
 | |
|     if (l != list || cellWidth == -1)
 | |
|       return null;
 | |
| 
 | |
|     int minIndex = Math.min(index1, index2);
 | |
|     int maxIndex = Math.max(index1, index2);
 | |
|     Point loc = indexToLocation(list, minIndex);
 | |
| 
 | |
|     // When the layoutOrientation is VERTICAL, then the width == the list
 | |
|     // width. Otherwise the cellWidth field is used.
 | |
|     int width = cellWidth;
 | |
|     if (l.getLayoutOrientation() == JList.VERTICAL)
 | |
|       width = l.getWidth();
 | |
| 
 | |
|     Rectangle bounds = new Rectangle(loc.x, loc.y, width,
 | |
|                                      getCellHeight(minIndex));
 | |
|     for (int i = minIndex + 1; i <= maxIndex; i++)
 | |
|       {
 | |
|         Point hiLoc = indexToLocation(list, i);
 | |
|         bounds = SwingUtilities.computeUnion(hiLoc.x, hiLoc.y, width,
 | |
|                                              getCellHeight(i), bounds);
 | |
|       }
 | |
| 
 | |
|     return bounds;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Calculates the maximum cell height.
 | |
|    *
 | |
|    * @param index the index of the cell
 | |
|    *
 | |
|    * @return the maximum cell height
 | |
|    */
 | |
|   private int getCellHeight(int index)
 | |
|   {
 | |
|     int height = cellHeight;
 | |
|     if (height <= 0)
 | |
|       {
 | |
|         if (list.getLayoutOrientation() == JList.VERTICAL)
 | |
|           height = getRowHeight(index);
 | |
|         else
 | |
|           {
 | |
|             for (int j = 0; j < cellHeights.length; j++)
 | |
|               height = Math.max(height, cellHeights[j]);
 | |
|           }
 | |
|       }
 | |
|     return height;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Calculate the Y coordinate of the upper edge of a particular row,
 | |
|    * considering the Y coordinate <code>0</code> to occur at the top of the
 | |
|    * list.
 | |
|    *
 | |
|    * @param row The row to calculate the Y coordinate of
 | |
|    *
 | |
|    * @return The Y coordinate of the specified row, or <code>-1</code> if
 | |
|    * the specified row number is invalid
 | |
|    */
 | |
|   protected int convertRowToY(int row)
 | |
|   {
 | |
|     int y = 0;
 | |
|     for (int i = 0; i < row; ++i)
 | |
|       {
 | |
|         int h = getRowHeight(i);
 | |
|         if (h == -1)
 | |
|           return -1;
 | |
|         y += h;
 | |
|       }
 | |
|     return y;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Calculate the row number containing a particular Y coordinate,
 | |
|    * considering the Y coodrinate <code>0</code> to occur at the top of the
 | |
|    * list.
 | |
|    *
 | |
|    * @param y0 The Y coordinate to calculate the row number for
 | |
|    *
 | |
|    * @return The row number containing the specified Y value, or <code>-1</code>
 | |
|    *         if the list model is empty
 | |
|    *
 | |
|    * @specnote This method is specified to return -1 for an invalid Y
 | |
|    *           coordinate. However, some simple tests show that the behaviour
 | |
|    *           is to return the index of the last list element for an Y
 | |
|    *           coordinate that lies outside of the list bounds (even for
 | |
|    *           negative indices). <code>-1</code>
 | |
|    *           is only returned if the list model is empty.
 | |
|    */
 | |
|   protected int convertYToRow(int y0)
 | |
|   {
 | |
|     if (list.getModel().getSize() == 0)
 | |
|       return -1;
 | |
| 
 | |
|     // When y0 < 0, then the JDK returns the maximum row index of the list. So
 | |
|     // do we.
 | |
|     if (y0 < 0)
 | |
|       return list.getModel().getSize() - 1;
 | |
| 
 | |
|     // Update the layout if necessary.
 | |
|     maybeUpdateLayoutState();
 | |
| 
 | |
|     int index = list.getModel().getSize() - 1;
 | |
| 
 | |
|     // If a fixed cell height is set, then we can work more efficient.
 | |
|     if (cellHeight > 0)
 | |
|       index = Math.min(y0 / cellHeight, index);
 | |
|     // If we have no fixed cell height, we must add up each cell height up
 | |
|     // to y0.
 | |
|     else
 | |
|       {
 | |
|         int h = 0;
 | |
|         for (int row = 0; row < cellHeights.length; ++row)
 | |
|           {
 | |
|             h += cellHeights[row];
 | |
|             if (y0 < h)
 | |
|               {
 | |
|                 index = row;
 | |
|                 break;
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Recomputes the {@link #cellHeights}, {@link #cellHeight}, and {@link
 | |
|    * #cellWidth} properties by examining the variouis properties of the
 | |
|    * {@link JList}.
 | |
|    */
 | |
|   protected void updateLayoutState()
 | |
|   {
 | |
|     int nrows = list.getModel().getSize();
 | |
|     cellHeight = -1;
 | |
|     cellWidth = -1;
 | |
|     if (cellHeights == null || cellHeights.length != nrows)
 | |
|       cellHeights = new int[nrows];
 | |
|     ListCellRenderer rend = list.getCellRenderer();
 | |
|     // Update the cellHeight(s) fields.
 | |
|     int fixedCellHeight = list.getFixedCellHeight();
 | |
|     if (fixedCellHeight > 0)
 | |
|       {
 | |
|         cellHeight = fixedCellHeight;
 | |
|         cellHeights = null;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         cellHeight = -1;
 | |
|         for (int i = 0; i < nrows; ++i)
 | |
|           {
 | |
|             Component flyweight =
 | |
|               rend.getListCellRendererComponent(list,
 | |
|                       list.getModel().getElementAt(i),
 | |
|                       i, list.isSelectedIndex(i),
 | |
|                       list.getSelectionModel().getAnchorSelectionIndex() == i);
 | |
|             Dimension dim = flyweight.getPreferredSize();
 | |
|             cellHeights[i] = dim.height;
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     // Update the cellWidth field.
 | |
|     int fixedCellWidth = list.getFixedCellWidth();
 | |
|     if (fixedCellWidth > 0)
 | |
|       cellWidth = fixedCellWidth;
 | |
|     else
 | |
|       {
 | |
|         for (int i = 0; i < nrows; ++i)
 | |
|           {
 | |
|             Component flyweight =
 | |
|               rend.getListCellRendererComponent(list,
 | |
|                                                 list.getModel().getElementAt(i),
 | |
|                                                 i, list.isSelectedIndex(i),
 | |
|                                                 list.getSelectionModel().getAnchorSelectionIndex() == i);
 | |
|             Dimension dim = flyweight.getPreferredSize();
 | |
|             cellWidth = Math.max(cellWidth, dim.width);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Calls {@link #updateLayoutState} if {@link #updateLayoutStateNeeded}
 | |
|    * is nonzero, then resets {@link #updateLayoutStateNeeded} to zero.
 | |
|    */
 | |
|   protected void maybeUpdateLayoutState()
 | |
|   {
 | |
|     if (updateLayoutStateNeeded != 0 || !list.isValid())
 | |
|       {
 | |
|         updateLayoutState();
 | |
|         updateLayoutStateNeeded = 0;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new BasicListUI object.
 | |
|    */
 | |
|   public BasicListUI()
 | |
|   {
 | |
|     updateLayoutStateNeeded = 1;
 | |
|     rendererPane = new CellRendererPane();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Installs various default settings (mostly colors) from the {@link
 | |
|    * UIDefaults} into the {@link JList}
 | |
|    *
 | |
|    * @see #uninstallDefaults
 | |
|    */
 | |
|   protected void installDefaults()
 | |
|   {
 | |
|     LookAndFeel.installColorsAndFont(list, "List.background",
 | |
|                                      "List.foreground", "List.font");
 | |
|     list.setSelectionForeground(UIManager.getColor("List.selectionForeground"));
 | |
|     list.setSelectionBackground(UIManager.getColor("List.selectionBackground"));
 | |
|     list.setOpaque(true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Resets to <code>null</code> those defaults which were installed in
 | |
|    * {@link #installDefaults}
 | |
|    */
 | |
|   protected void uninstallDefaults()
 | |
|   {
 | |
|     list.setForeground(null);
 | |
|     list.setBackground(null);
 | |
|     list.setSelectionForeground(null);
 | |
|     list.setSelectionBackground(null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Attaches all the listeners we have in the UI class to the {@link
 | |
|    * JList}, its model and its selection model.
 | |
|    *
 | |
|    * @see #uninstallListeners
 | |
|    */
 | |
|   protected void installListeners()
 | |
|   {
 | |
|     if (focusListener == null)
 | |
|       focusListener = createFocusListener();
 | |
|     list.addFocusListener(focusListener);
 | |
|     if (listDataListener == null)
 | |
|       listDataListener = createListDataListener();
 | |
|     list.getModel().addListDataListener(listDataListener);
 | |
|     if (listSelectionListener == null)
 | |
|       listSelectionListener = createListSelectionListener();
 | |
|     list.addListSelectionListener(listSelectionListener);
 | |
|     if (mouseInputListener == null)
 | |
|       mouseInputListener = createMouseInputListener();
 | |
|     list.addMouseListener(mouseInputListener);
 | |
|     list.addMouseMotionListener(mouseInputListener);
 | |
|     if (propertyChangeListener == null)
 | |
|       propertyChangeListener = createPropertyChangeListener();
 | |
|     list.addPropertyChangeListener(propertyChangeListener);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Detaches all the listeners we attached in {@link #installListeners}.
 | |
|    */
 | |
|   protected void uninstallListeners()
 | |
|   {
 | |
|     list.removeFocusListener(focusListener);
 | |
|     list.getModel().removeListDataListener(listDataListener);
 | |
|     list.removeListSelectionListener(listSelectionListener);
 | |
|     list.removeMouseListener(mouseInputListener);
 | |
|     list.removeMouseMotionListener(mouseInputListener);
 | |
|     list.removePropertyChangeListener(propertyChangeListener);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Installs keyboard actions for this UI in the {@link JList}.
 | |
|    */
 | |
|   protected void installKeyboardActions()
 | |
|   {
 | |
|     // Install UI InputMap.
 | |
|     InputMap focusInputMap = (InputMap) UIManager.get("List.focusInputMap");
 | |
|     SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED,
 | |
|                                      focusInputMap);
 | |
| 
 | |
|     // Install UI ActionMap.
 | |
|     ActionMap am = (ActionMap) UIManager.get("List.actionMap");
 | |
|     if (am == null)
 | |
|       {
 | |
|         // Create the actionMap once and store it in the current UIDefaults
 | |
|         // for use in other components.
 | |
|         am = new ActionMapUIResource();
 | |
|         ListAction action;
 | |
|         action = new ListAction("selectPreviousRow");
 | |
|         am.put("selectPreviousRow", action);
 | |
|         action = new ListAction("selectNextRow");
 | |
|         am.put("selectNextRow", action);
 | |
|         action = new ListAction("selectPreviousRowExtendSelection");
 | |
|         am.put("selectPreviousRowExtendSelection", action);
 | |
|         action = new ListAction("selectNextRowExtendSelection");
 | |
|         am.put("selectNextRowExtendSelection", action);
 | |
| 
 | |
|         action = new ListAction("selectPreviousColumn");
 | |
|         am.put("selectPreviousColumn", action);
 | |
|         action = new ListAction("selectNextColumn");
 | |
|         am.put("selectNextColumn", action);
 | |
|         action = new ListAction("selectPreviousColumnExtendSelection");
 | |
|         am.put("selectPreviousColumnExtendSelection", action);
 | |
|         action = new ListAction("selectNextColumnExtendSelection");
 | |
|         am.put("selectNextColumnExtendSelection", action);
 | |
| 
 | |
|         action = new ListAction("selectFirstRow");
 | |
|         am.put("selectFirstRow", action);
 | |
|         action = new ListAction("selectLastRow");
 | |
|         am.put("selectLastRow", action);
 | |
|         action = new ListAction("selectFirstRowExtendSelection");
 | |
|         am.put("selectFirstRowExtendSelection", action);
 | |
|         action = new ListAction("selectLastRowExtendSelection");
 | |
|         am.put("selectLastRowExtendSelection", action);
 | |
| 
 | |
|         action = new ListAction("scrollUp");
 | |
|         am.put("scrollUp", action);
 | |
|         action = new ListAction("scrollUpExtendSelection");
 | |
|         am.put("scrollUpExtendSelection", action);
 | |
|         action = new ListAction("scrollDown");
 | |
|         am.put("scrollDown", action);
 | |
|         action = new ListAction("scrollDownExtendSelection");
 | |
|         am.put("scrollDownExtendSelection", action);
 | |
| 
 | |
|         action = new ListAction("selectAll");
 | |
|         am.put("selectAll", action);
 | |
|         action = new ListAction("clearSelection");
 | |
|         am.put("clearSelection", action);
 | |
| 
 | |
|         am.put("copy", TransferHandler.getCopyAction());
 | |
|         am.put("cut", TransferHandler.getCutAction());
 | |
|         am.put("paste", TransferHandler.getPasteAction());
 | |
| 
 | |
|         UIManager.put("List.actionMap", am);
 | |
|       }
 | |
| 
 | |
|     SwingUtilities.replaceUIActionMap(list, am);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Uninstalls keyboard actions for this UI in the {@link JList}.
 | |
|    */
 | |
|   protected void uninstallKeyboardActions()
 | |
|   {
 | |
|     // Uninstall the InputMap.
 | |
|     InputMap im = SwingUtilities.getUIInputMap(list, JComponent.WHEN_FOCUSED);
 | |
|     if (im instanceof UIResource)
 | |
|       SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null);
 | |
| 
 | |
|     // Uninstall the ActionMap.
 | |
|     if (SwingUtilities.getUIActionMap(list) instanceof UIResource)
 | |
|       SwingUtilities.replaceUIActionMap(list, null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Installs the various aspects of the UI in the {@link JList}. In
 | |
|    * particular, calls {@link #installDefaults}, {@link #installListeners}
 | |
|    * and {@link #installKeyboardActions}. Also saves a reference to the
 | |
|    * provided component, cast to a {@link JList}.
 | |
|    *
 | |
|    * @param c The {@link JList} to install the UI into
 | |
|    */
 | |
|   public void installUI(final JComponent c)
 | |
|   {
 | |
|     super.installUI(c);
 | |
|     list = (JList) c;
 | |
|     installDefaults();
 | |
|     installListeners();
 | |
|     installKeyboardActions();
 | |
|     maybeUpdateLayoutState();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Uninstalls all the aspects of the UI which were installed in {@link
 | |
|    * #installUI}. When finished uninstalling, drops the saved reference to
 | |
|    * the {@link JList}.
 | |
|    *
 | |
|    * @param c Ignored; the UI is uninstalled from the {@link JList}
 | |
|    * reference saved during the call to {@link #installUI}
 | |
|    */
 | |
|   public void uninstallUI(final JComponent c)
 | |
|   {
 | |
|     uninstallKeyboardActions();
 | |
|     uninstallListeners();
 | |
|     uninstallDefaults();
 | |
|     list = null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets the size this list would prefer to assume. This is calculated by
 | |
|    * calling {@link #getCellBounds} over the entire list.
 | |
|    *
 | |
|    * @param c Ignored; uses the saved {@link JList} reference
 | |
|    *
 | |
|    * @return DOCUMENT ME!
 | |
|    */
 | |
|   public Dimension getPreferredSize(JComponent c)
 | |
|   {
 | |
|     maybeUpdateLayoutState();
 | |
|     int size = list.getModel().getSize();
 | |
|     int visibleRows = list.getVisibleRowCount();
 | |
|     int layoutOrientation = list.getLayoutOrientation();
 | |
| 
 | |
|     int h;
 | |
|     int w;
 | |
|     int maxCellHeight = cellHeight;
 | |
|     if (maxCellHeight <= 0)
 | |
|       {
 | |
|         for (int i = 0; i < cellHeights.length; i++)
 | |
|           maxCellHeight = Math.max(maxCellHeight, cellHeights[i]);
 | |
|       }
 | |
|     if (layoutOrientation == JList.HORIZONTAL_WRAP)
 | |
|       {
 | |
|         if (visibleRows > 0)
 | |
|           {
 | |
|             // We cast to double here to force double divisions.
 | |
|             double modelSize = size;
 | |
|             int neededColumns = (int) Math.ceil(modelSize / visibleRows);
 | |
|             int adjustedRows = (int) Math.ceil(modelSize / neededColumns);
 | |
|             h = maxCellHeight * adjustedRows;
 | |
|             w = cellWidth * neededColumns;
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             int neededColumns = Math.min(1, list.getWidth() / cellWidth);
 | |
|             h = size / neededColumns * maxCellHeight;
 | |
|             w = neededColumns * cellWidth;
 | |
|           }
 | |
|       }
 | |
|     else if (layoutOrientation == JList.VERTICAL_WRAP)
 | |
|       {
 | |
|         if (visibleRows > 0)
 | |
|           h = visibleRows * maxCellHeight;
 | |
|         else
 | |
|           h = Math.max(list.getHeight(), maxCellHeight);
 | |
|         int neededColumns = h / maxCellHeight;
 | |
|         w = cellWidth * neededColumns;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         if (list.getFixedCellWidth() > 0)
 | |
|           w = list.getFixedCellWidth();
 | |
|         else
 | |
|           w = cellWidth;
 | |
|         if (list.getFixedCellHeight() > 0)
 | |
|           // FIXME: We need to add some cellVerticalMargins here, according
 | |
|           // to the specs.
 | |
|           h = list.getFixedCellHeight() * size;
 | |
|         else
 | |
|           h = maxCellHeight * size;
 | |
|       }
 | |
|     Insets insets = list.getInsets();
 | |
|     Dimension retVal = new Dimension(w + insets.left + insets.right,
 | |
|                                      h + insets.top + insets.bottom);
 | |
|     return retVal;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Paints a single cell in the list.
 | |
|    *
 | |
|    * @param g The graphics context to paint in
 | |
|    * @param row The row number to paint
 | |
|    * @param bounds The bounds of the cell to paint, assuming a coordinate
 | |
|    * system beginning at <code>(0,0)</code> in the upper left corner of the
 | |
|    * list
 | |
|    * @param rend A cell renderer to paint with
 | |
|    * @param data The data to provide to the cell renderer
 | |
|    * @param sel A selection model to provide to the cell renderer
 | |
|    * @param lead The lead selection index of the list
 | |
|    */
 | |
|   protected void paintCell(Graphics g, int row, Rectangle bounds,
 | |
|                  ListCellRenderer rend, ListModel data,
 | |
|                  ListSelectionModel sel, int lead)
 | |
|   {
 | |
|     boolean isSel = list.isSelectedIndex(row);
 | |
|     boolean hasFocus = (list.getLeadSelectionIndex() == row) && BasicListUI.this.list.hasFocus();
 | |
|     Component comp = rend.getListCellRendererComponent(list,
 | |
|                                                        data.getElementAt(row),
 | |
|                                                        row, isSel, hasFocus);
 | |
|     rendererPane.paintComponent(g, comp, list, bounds);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Paints the list by repeatedly calling {@link #paintCell} for each visible
 | |
|    * cell in the list.
 | |
|    *
 | |
|    * @param g The graphics context to paint with
 | |
|    * @param c Ignored; uses the saved {@link JList} reference
 | |
|    */
 | |
|   public void paint(Graphics g, JComponent c)
 | |
|   {
 | |
|     int nrows = list.getModel().getSize();
 | |
|     if (nrows == 0)
 | |
|       return;
 | |
| 
 | |
|     maybeUpdateLayoutState();
 | |
|     ListCellRenderer render = list.getCellRenderer();
 | |
|     ListModel model = list.getModel();
 | |
|     ListSelectionModel sel = list.getSelectionModel();
 | |
|     int lead = sel.getLeadSelectionIndex();
 | |
|     Rectangle clip = g.getClipBounds();
 | |
| 
 | |
|     int startIndex = locationToIndex(list, new Point(clip.x, clip.y));
 | |
|     int endIndex = locationToIndex(list, new Point(clip.x + clip.width,
 | |
|                                              clip.y + clip.height));
 | |
| 
 | |
|     for (int row = startIndex; row <= endIndex; ++row)
 | |
|       {
 | |
|         Rectangle bounds = getCellBounds(list, row, row);
 | |
|         if (bounds != null && bounds.intersects(clip))
 | |
|           paintCell(g, row, bounds, render, model, sel, lead);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Computes the index of a list cell given a point within the list. If the
 | |
|    * location lies outside the bounds of the list, the greatest index in the
 | |
|    * list model is returned.
 | |
|    *
 | |
|    * @param l the list which on which the computation is based on
 | |
|    * @param location the coordinates
 | |
|    *
 | |
|    * @return the index of the list item that is located at the given
 | |
|    *         coordinates or <code>-1</code> if the list model is empty
 | |
|    */
 | |
|   public int locationToIndex(JList l, Point location)
 | |
|   {
 | |
|     int layoutOrientation = list.getLayoutOrientation();
 | |
|     int index = -1;
 | |
|     switch (layoutOrientation)
 | |
|       {
 | |
|       case JList.VERTICAL:
 | |
|         index = convertYToRow(location.y);
 | |
|         break;
 | |
|       case JList.HORIZONTAL_WRAP:
 | |
|         // determine visible rows and cells per row
 | |
|         int maxCellHeight = getCellHeight(0);
 | |
|         int visibleRows = list.getHeight() / maxCellHeight;
 | |
|         int cellsPerRow = -1;
 | |
|         int numberOfItems = list.getModel().getSize();
 | |
|         cellsPerRow = numberOfItems / visibleRows + 1;
 | |
| 
 | |
|         // determine index for the given location
 | |
|         int cellsPerColumn = numberOfItems / cellsPerRow + 1;
 | |
|         int gridX = Math.min(location.x / cellWidth, cellsPerRow - 1);
 | |
|         int gridY = Math.min(location.y / maxCellHeight, cellsPerColumn);
 | |
|         index = gridX + gridY * cellsPerRow;
 | |
|         break;
 | |
|       case JList.VERTICAL_WRAP:
 | |
|         // determine visible rows and cells per column
 | |
|         int maxCellHeight2 = getCellHeight(0);
 | |
|         int visibleRows2 = list.getHeight() / maxCellHeight2;
 | |
|         int numberOfItems2 = list.getModel().getSize();
 | |
|         int cellsPerRow2 = numberOfItems2 / visibleRows2 + 1;
 | |
| 
 | |
|         int gridX2 = Math.min(location.x / cellWidth, cellsPerRow2 - 1);
 | |
|         int gridY2 = Math.min(location.y / maxCellHeight2, visibleRows2);
 | |
|         index = gridY2 + gridX2 * visibleRows2;
 | |
|         break;
 | |
|       }
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   public Point indexToLocation(JList l, int index)
 | |
|   {
 | |
|     int layoutOrientation = list.getLayoutOrientation();
 | |
|     Point loc = null;
 | |
|     switch (layoutOrientation)
 | |
|       {
 | |
|       case JList.VERTICAL:
 | |
|         loc = new Point(0, convertRowToY(index));
 | |
|         break;
 | |
|       case JList.HORIZONTAL_WRAP:
 | |
|         // determine visible rows and cells per row
 | |
|         int maxCellHeight = getCellHeight(0);
 | |
|         int visibleRows = list.getHeight() / maxCellHeight;
 | |
|         int numberOfCellsPerRow = -1;
 | |
|         int numberOfItems = list.getModel().getSize();
 | |
|         numberOfCellsPerRow = numberOfItems / visibleRows + 1;
 | |
| 
 | |
|         // compute coordinates inside the grid
 | |
|         int gridX = index % numberOfCellsPerRow;
 | |
|         int gridY = index / numberOfCellsPerRow;
 | |
|         int locX = gridX * cellWidth;
 | |
|         int locY;
 | |
|         locY = gridY * maxCellHeight;
 | |
|         loc = new Point(locX, locY);
 | |
|         break;
 | |
|       case JList.VERTICAL_WRAP:
 | |
|         // determine visible rows and cells per column
 | |
|         int maxCellHeight2 = getCellHeight(0);
 | |
|         int visibleRows2 = list.getHeight() / maxCellHeight2;
 | |
|         // compute coordinates inside the grid
 | |
|         if (visibleRows2 > 0)
 | |
|           {
 | |
|             int gridY2 = index % visibleRows2;
 | |
|             int gridX2 = index / visibleRows2;
 | |
|             int locX2 = gridX2 * cellWidth;
 | |
|             int locY2 = gridY2 * maxCellHeight2;
 | |
|             loc = new Point(locX2, locY2);
 | |
|           }
 | |
|         else
 | |
|           loc = new Point(0, convertRowToY(index));
 | |
|         break;
 | |
|       }
 | |
|     return loc;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates and returns the focus listener for this UI.
 | |
|    *
 | |
|    * @return the focus listener for this UI
 | |
|    */
 | |
|   protected FocusListener createFocusListener()
 | |
|   {
 | |
|     return new FocusHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates and returns the list data listener for this UI.
 | |
|    *
 | |
|    * @return the list data listener for this UI
 | |
|    */
 | |
|   protected ListDataListener createListDataListener()
 | |
|   {
 | |
|     return new ListDataHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates and returns the list selection listener for this UI.
 | |
|    *
 | |
|    * @return the list selection listener for this UI
 | |
|    */
 | |
|   protected ListSelectionListener createListSelectionListener()
 | |
|   {
 | |
|     return new ListSelectionHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates and returns the mouse input listener for this UI.
 | |
|    *
 | |
|    * @return the mouse input listener for this UI
 | |
|    */
 | |
|   protected MouseInputListener createMouseInputListener()
 | |
|   {
 | |
|     return new MouseInputHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates and returns the property change listener for this UI.
 | |
|    *
 | |
|    * @return the property change listener for this UI
 | |
|    */
 | |
|   protected PropertyChangeListener createPropertyChangeListener()
 | |
|   {
 | |
|     return new PropertyChangeHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Selects the next list item and force it to be visible.
 | |
|    */
 | |
|   protected void selectNextIndex()
 | |
|   {
 | |
|     int index = list.getSelectionModel().getLeadSelectionIndex();
 | |
|     if (index < list.getModel().getSize() - 1)
 | |
|       {
 | |
|         index++;
 | |
|         list.setSelectedIndex(index);
 | |
|       }
 | |
|     list.ensureIndexIsVisible(index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Selects the previous list item and force it to be visible.
 | |
|    */
 | |
|   protected void selectPreviousIndex()
 | |
|   {
 | |
|     int index = list.getSelectionModel().getLeadSelectionIndex();
 | |
|     if (index > 0)
 | |
|       {
 | |
|         index--;
 | |
|         list.setSelectedIndex(index);
 | |
|       }
 | |
|     list.ensureIndexIsVisible(index);
 | |
|   }
 | |
| }
 |