home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / MacListUI.java < prev    next >
Text File  |  1998-02-26  |  12KB  |  452 lines

  1. /*
  2.  * %W% %E%
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21. package com.sun.java.swing.plaf.mac;
  22.  
  23. import com.sun.java.swing.*;
  24. import com.sun.java.swing.event.*;
  25. import com.sun.java.swing.plaf.*;
  26.  
  27. import java.awt.*;
  28. import java.awt.event.*;
  29.  
  30. import java.beans.PropertyChangeListener;
  31. import java.beans.PropertyChangeEvent;
  32.  
  33. import com.sun.java.swing.plaf.basic.BasicListUI;
  34. import java.io.Serializable;
  35.  
  36.  
  37. /**
  38.  * A Mac L&F implementation of ListUI.
  39.  *
  40.  * To add icons you will need to:
  41.  * <ul>
  42.  * <li> Create your own CellRenderer class. For an example see the Mac UI for JTree.
  43.  * <li> Extend this class and override configureList to create your own CellRenderer.
  44.  * </ul>
  45.  * Warning: serialized objects of this class will not be compatible with
  46.  * future swing releases.  The current serialization support is appropriate
  47.  * for short term storage or RMI between Swing1.0 applications.  It will
  48.  * not be possible to load serialized Swing1.0 objects with future releases
  49.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  50.  * baseline for the serialized form of Swing objects.
  51.  *
  52.  * @version 1.15 10/23/97
  53.  * @author Hans Muller
  54.  */
  55.  
  56. public class MacListUI extends BasicListUI
  57. {
  58.     Window parentWindow = null;
  59.     MacListAncestorListener anAncestorListener;
  60.     boolean activated = false;
  61.     
  62.     //Override so the entire component is not painted with the background color
  63.      public void update(Graphics g, JComponent c) {
  64.         paint(g, c);
  65.     }
  66.     
  67.     /**
  68.      * If the list is opaque, paint its background.
  69.      * Subclasses may want to override this method rather than paint().
  70.      * 
  71.      * @see #paint
  72.      */
  73.     protected void paintBackground(Graphics g)
  74.     {
  75.         g.setColor(list.getBackground());
  76.         Rectangle viewRect = new Rectangle(list.getSize());
  77.  
  78.         Insets i = list.getInsets();
  79.         
  80.         viewRect.x += i.left;
  81.         viewRect.y += i.top;
  82.         viewRect.width -= (i.right + viewRect.x);
  83.         viewRect.height -= (i.bottom + viewRect.y);
  84.         
  85.         g.fillRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
  86.     }
  87.  
  88.  
  89.     /**
  90.      * Paint the rows that intersect the Graphics objects clipRect.  This
  91.      * method calls paintBackground and paintCell as necessary.  Subclasses
  92.      * may want to override these methods.
  93.      * 
  94.      * @see #paintBackground
  95.      * @see #paintCell
  96.      */
  97.     public void paint(Graphics g, JComponent c) 
  98.     {
  99.     maybeUpdateLayoutState();
  100.  
  101.     ListCellRenderer renderer = list.getCellRenderer();
  102.     ListModel dataModel = list.getModel();
  103.     ListSelectionModel selModel = list.getSelectionModel();
  104.  
  105.     if (renderer == null) {
  106.         return;
  107.     }
  108.  
  109.     paintBackground(g);
  110.     
  111.     Rectangle rect = list.getBounds();
  112.         
  113. //    list.getBorder().paintBorder(list,g, rect.x, rect.y, rect.width - 1, rect.height -1);
  114.  
  115.     /* Compute the area we're going to paint in terms of the affected
  116.      * rows (firstPaintRow, lastPaintRow), and the clip bounds.
  117.      */
  118.        
  119.     Rectangle paintBounds = g.getClipBounds();
  120.     int firstPaintRow = convertYToRow(paintBounds.y);
  121.     int lastPaintRow = convertYToRow((paintBounds.y + paintBounds.height) - 1);
  122.  
  123.     if (firstPaintRow == -1) {
  124.         firstPaintRow = 0;
  125.     }
  126.     if (lastPaintRow == -1) {
  127.         lastPaintRow = dataModel.getSize() - 1;
  128.     }
  129.  
  130.     Rectangle rowBounds = getCellBounds(list, firstPaintRow, firstPaintRow);
  131.     if (rowBounds == null) {
  132.         return;
  133.     }
  134.  
  135.     int leadIndex = list.getLeadSelectionIndex();
  136.  
  137.     for(int row = firstPaintRow; row <= lastPaintRow; row++) {
  138.         rowBounds.height = getRowHeight(row);
  139.  
  140.         /* Set the clip rect to be the intersection of rowBounds 
  141.          * and paintBounds and then paint the cell.
  142.          */
  143.  
  144.         g.setClip(rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height);
  145.         g.clipRect(paintBounds.x, paintBounds.y, paintBounds.width, paintBounds.height);
  146.  
  147.         paintCell(g, row, rowBounds, renderer, dataModel, selModel, leadIndex);
  148.  
  149.         rowBounds.y += rowBounds.height;
  150.     }
  151.     }
  152.  
  153.     /**
  154.      * Remove the listeners for the JList, its model, and its 
  155.      * selectionModel.  All of the listener fields, are reset to 
  156.      * null here.  This method is called at uninstallUI() time,
  157.      * it should be kept in sync with addListListeners.
  158.      *
  159.      * @see #uninstallUI
  160.      * @see #addListListeners
  161.      */
  162.     protected void removeListListeners()
  163.     {
  164.         super.removeListListeners();
  165.  
  166.         list.removeAncestorListener(anAncestorListener);
  167.     }
  168.  
  169.  
  170.     /**
  171.      * Initialize JList properties, e.g. font, foreground, and background,
  172.      * and add the CellRendererPane.  The font, foreground, and background
  173.      * properties are only set if their current value is either null
  174.      * or a UIResource, other properties are set if the current
  175.      * value is null.
  176.      * 
  177.      * @see #unconfigureList
  178.      * @see #installUI
  179.      * @see CellRendererPane
  180.      */
  181.     protected void configureList() 
  182.     {   
  183.         if(list.getCellRenderer() == null)     
  184.             list.setCellRenderer(new MacListCellRenderer());
  185.         
  186.         super.configureList();
  187.         
  188.         list.setBorder(MacBorderFactory.getFocusBorder());
  189.     }
  190.  
  191.  
  192.  
  193.     /**
  194.      * Initializes <code>this.list</code> by calling <code>configureList()</code>,
  195.      * <code>addListListeners()</code>, and <code>registerKeyboardActions()</code>
  196.      * in order.
  197.      * 
  198.      * @see #configureList
  199.      * @see #addListListeners
  200.      * @see #registerKeyboardActions
  201.      */
  202.     public void installUI(JComponent list) 
  203.     {
  204.     this.list = (JList)list;
  205.     configureList();
  206.     addListListeners();
  207.     registerKeyboardActions();
  208.     
  209.     //set up listener so we know when addNotify and removeNotify are called
  210.         anAncestorListener = new MacListAncestorListener();
  211.         list.addAncestorListener(anAncestorListener);
  212.     }
  213.  
  214.  
  215.     /**
  216.      * Uninitializes <code>this.list</code> by calling <code>removeListListeners()</code>,
  217.      * <code>unregisterKeyboardActions()</code>, and <code>unconfigureList()</code>
  218.      * in order.  Sets this.list to null.
  219.      * 
  220.      * @see #removeListListeners
  221.      * @see #unregisterKeyboardActions
  222.      * @see #unconfigureList
  223.      */
  224.     public void uninstallUI(JComponent c) 
  225.     {
  226.     removeListListeners();
  227.     unregisterKeyboardActions();
  228.     unconfigureList();
  229.     
  230.     cellWidth = cellHeight = -1;
  231.     cellHeights = null;
  232.     
  233.     this.list = null;
  234.     }
  235.  
  236.  
  237.     /**
  238.      * Returns a new instance of BasicListUI.  BasicListUI delegates are
  239.      * allocated one per JList.
  240.      * 
  241.      * @return A new ListUI implementation for the Mac look and feel.
  242.      */
  243.     public static ComponentUI createUI(JComponent list) {
  244.     return new MacListUI();
  245.     }
  246.  
  247.  
  248.  
  249.     /** 
  250.      * @return The bounds of the index'th cell.
  251.      * @see ListUI#getCellBounds
  252.      */
  253.     public Rectangle getCellBounds(JList list, int index1, int index2) {
  254.     maybeUpdateLayoutState();
  255.  
  256.     int minIndex = Math.min(index1, index2);
  257.     int maxIndex = Math.max(index1, index2);
  258.     int minY = convertRowToY(minIndex);
  259.     int maxY = convertRowToY(maxIndex);
  260.  
  261.     if ((minY == -1) || (maxY == -1)) {
  262.         return null;
  263.     }
  264.  
  265.     maxY += getRowHeight(maxIndex);
  266.     Insets i = list.getInsets();
  267.     return new Rectangle(i.left, minY, list.getWidth() - i.left - i.right, maxY - minY);
  268.     }
  269.  
  270.  
  271.  
  272.     /**
  273.      * Convert the JList relative coordinate to the row that contains it,
  274.      * based on the current layout.  If y0 doesn't fall within any row, 
  275.      * return -1.
  276.      * 
  277.      * @return The row that contains y0, or -1.
  278.      * @see #getRowHeight
  279.      * @see #updateLayoutState
  280.      */
  281.     protected int convertYToRow(int y0)
  282.     {
  283.     int nrows = list.getModel().getSize();
  284.  
  285.     Dimension dim = list.getSize();
  286.     Insets insets = list.getInsets();
  287.     
  288.     //make sure we are in the content area
  289.     if((y0 <= insets.top) || (y0 > dim.height - insets.bottom))
  290.         return -1;
  291.     
  292.     if (cellHeights == null) 
  293.     {
  294.         int row = (cellHeight == 0) ? 0 : (y0 - insets.top)/cellHeight;
  295.          return ((row < 0) || (row >= nrows)) ? -1 : row;
  296.     }
  297.     else {
  298.         int y = insets.top;
  299.         int row = 0;
  300.  
  301.         for(int i = 0; i < nrows; i++) {
  302.         if ((y0 >= y) && (y0 < y + cellHeights[i])) {
  303.             return row;
  304.         }
  305.         y += cellHeights[i];
  306.         row += 1;
  307.         }
  308.         return -1;
  309.     }
  310.     }
  311.  
  312.  
  313.     /**
  314.      * Return the JList relative Y coordinate of the origin of the specified 
  315.      * row or -1 if row isn't valide.
  316.      * 
  317.      * @return The Y coordinate of the origin of row, or -1.
  318.      * @see #getRowHeight
  319.      * @see #updateLayoutState
  320.      */
  321.     protected int convertRowToY(int row) 
  322.     {
  323.     int nrows = list.getModel().getSize();
  324.     Insets insets = list.getInsets();
  325.     
  326.     if ((row < 0) || (row > nrows)) {
  327.         return -1;
  328.     }
  329.  
  330.     if (cellHeights == null) {
  331.         return cellHeight * row + insets.top;;
  332.     }
  333.     else {
  334.         int y = insets.top;
  335.         for(int i = 0; i < row; i++) {
  336.         y += cellHeights[i];
  337.         }
  338.         return y;
  339.     }
  340.     }
  341.  
  342.  
  343.     public void setActivated(boolean activated)
  344.     {
  345.         this.activated = activated;
  346.     }
  347.     
  348.     public boolean isActivated()
  349.     {
  350.         return activated;
  351.     }
  352.     
  353.     public JList getList()
  354.     {
  355.         return list;
  356.     }
  357.     
  358.     class MacListAncestorListener implements com.sun.java.swing.event.AncestorListener
  359.     {
  360.         ListWindowAdapter aListWindowAdapter;
  361.         
  362.         /**
  363.          * Called when the source or one of its ancestors is made visible
  364.          * either by setVisible(true) being called or by its being
  365.          * added to the component hierarchy.  The method is only called
  366.          * if the source has actually become visible.  For this to be true
  367.          * all its parents must be visible and it must be in a hierarchy
  368.          * rooted at a Window
  369.          */
  370.         public void ancestorAdded(com.sun.java.swing.event.AncestorEvent event)
  371.         {
  372.             Component parent = null;
  373.             JList c = getList();
  374.             int hHeight = 0, vWidth = 0;
  375.             
  376.             Object object = event.getSource();
  377.             if(object == c )
  378.                  parent = c.getParent();
  379.             
  380.                 while((parent != null) && (!(parent instanceof Window)))
  381.                     parent = parent.getParent();
  382.                     
  383.                 
  384.             if(parent != null)
  385.             {
  386.                 parentWindow = (Window)parent;
  387.                 
  388.                 aListWindowAdapter = new ListWindowAdapter();
  389.                 parentWindow.addWindowListener(aListWindowAdapter);
  390.             }
  391.         }
  392.     
  393.         /**
  394.          * Called when the source or one of its ancestors is made invisible
  395.          * either by setVisible(false) being called or by its being
  396.          * remove from the component hierarchy.  The method is only called
  397.          * if the source has actually become invisible.  For this to be true
  398.          * at least one of its parents must by invisible or it is not in
  399.          * a hierarchy rooted at a Window
  400.          */
  401.         public void ancestorRemoved(com.sun.java.swing.event.AncestorEvent event)
  402.         {
  403.             if(parentWindow != null)
  404.                 parentWindow.removeWindowListener(aListWindowAdapter);
  405.         }
  406.     
  407.         /**
  408.          * Called when either the source or one of its ancestors is moved.
  409.          */
  410.         public void ancestorMoved(com.sun.java.swing.event.AncestorEvent event)
  411.         {
  412.         }
  413.     }
  414.     
  415.     class ListWindowAdapter extends java.awt.event.WindowAdapter
  416.     {
  417.         public void windowDeactivated(java.awt.event.WindowEvent event)
  418.         {
  419.             Object object = event.getSource();
  420.             if (object == parentWindow)
  421.                 ParentWindow_WindowDeactivated(event);
  422.         }
  423.  
  424.         public void windowActivated(java.awt.event.WindowEvent event)
  425.         {
  426.             Object object = event.getSource();
  427.             if (object == parentWindow)
  428.                 ParentWindow_WindowActivated(event);
  429.         }
  430.     }
  431.  
  432.     void ParentWindow_WindowActivated(java.awt.event.WindowEvent event)
  433.     {
  434.         setActivated(true);
  435.         
  436.         if(list != null)
  437.             list.repaint();
  438.     }
  439.  
  440.     void ParentWindow_WindowDeactivated(java.awt.event.WindowEvent event)
  441.     {
  442.         setActivated(false);
  443.         if(list != null)
  444.             list.repaint();
  445.     }
  446.  
  447. }
  448.  
  449.  
  450.     
  451.  
  452.