Highlighter.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:20k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: Highlighter.java,v 1.6 2005/10/13 08:59:54 kleopatra Exp $
  3.  *
  4.  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
  5.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.swingx.decorator;
  22. import java.awt.Color;
  23. import java.awt.Component;
  24. import javax.swing.BoundedRangeModel;
  25. import javax.swing.event.ChangeEvent;
  26. import javax.swing.event.ChangeListener;
  27. import javax.swing.event.EventListenerList;
  28. /**
  29.  * <p><code>Highlighter</code> is a lightweight mechanism to modify the behavior
  30.  * and attributes of cell renderers such as {@link javax.swing.ListCellRenderer},
  31.  * {@link javax.swing.table.TableCellRenderer}, and
  32.  * {@link javax.swing.tree.TreeCellRenderer} in a simple layered fashion.
  33.  * While cell renderers are split along component lines, highlighters provide a
  34.  * <em>common interface</em> for decorating cell renderers.
  35.  * <code>Highlighter</code> achieves this by vectoring access to all component-specific
  36.  * state and functionality through a {@link ComponentAdapter} object.</p>
  37.  *
  38.  * <p>The primary purpose of <code>Highlighter</code> is to decorate a cell
  39.  * renderer in <em>controlled</em> ways, such as by applying a different color
  40.  * or font to it. For example, {@link AlternateRowHighlighter} highlights cell
  41.  * renderers with alternating background colors. In data visualization components
  42.  * that support multiple columns with potentially different types of data, this
  43.  * highlighter imparts the same background color consistently across <em>all</em>
  44.  * columns of the {@link ComponentAdapter#target target} component
  45.  * regardless of the actual cell renderer registered for any specific column.
  46.  * Thus, the <code>Highlighter</code> mechanism is orthogonal to the cell
  47.  * rendering mechanism.</p>
  48.  *
  49.  * <p>To use <code>Highlighter</code> you must first set up a
  50.  * {@link HighlighterPipeline} using an array of <code>Highlighter</code> objects,
  51.  * and then call setHighlighters() on a data visualization component, passing in
  52.  * the highligher pipeline. If the array of highlighters is not null and is not
  53.  * empty, the highlighters are applied to the selected renderer for each cell in
  54.  * the order they appear in the array.
  55.  * When it is time to render a cell, the cell renderer is primed as usual, after
  56.  * which, the {@link Highlighter#highlight highlight} method of the first
  57.  * highlighter in the {@link HighlighterPipeline} is invoked. The prepared
  58.  * renderer, and a suitable {@link ComponentAdapter} object is passed to the
  59.  * <code>highlight</code> method. The highlighter is expected to modify the
  60.  * renderer in controlled ways, and return the modified renderer (or a substitute)
  61.  * that is passed to the next highlighter, if any, in the pipeline. The renderer
  62.  * returned by the <code>highlight</code> method of the last highlighter in the
  63.  * pipeline is ultimately used to render the cell.</p>
  64.  *
  65.  * <p>The <code>Highlighter</code> mechanism enables multiple degrees of
  66.  * freedom. In addition to specifying the actual cell renderer class, now you
  67.  * can also specify the number, order, and class of highlighter objects. Using
  68.  * highlighters is really simple, as shown by the following example:</p>
  69.  *
  70.  * <pre>
  71.   Highlighter[]   highlighters = new Highlighter[] {
  72.       new <b>AlternateRowHighlighter</b>(Color.white,
  73.                                          new Color(0xF0, 0xF0, 0xE0), null),
  74.       new <b>PatternHighlighter</b>(null, Color.red, "s.*", 0, 0)
  75.   };
  76.   HighlighterPipeline highlighterPipeline = new HighlighterPipeline(highlighters);
  77.   JXTable table = new JXTable();
  78.   table.setHighlighters(highlighterPipeline);
  79.  * </pre>
  80.  *
  81.  * <p>The above example allocates an array of <code>Highlighter</code> and populates
  82.  * it with a new {@link AlternateRowHighlighter} and {@link PatternHighlighter}.
  83.  * The first one in this example highlights all cells in odd rows with a white
  84.  * background, and all cells in even rows with a silver background, but it does
  85.  * not specify a foreground color explicitly. The second highlighter does not
  86.  * specify a background color explicitly, but sets the foreground color to red
  87.  * <em>if certain conditions are met</em> (see {@link PatternHighlighter} for
  88.  * more details). In this example, if the cells in the first column of any
  89.  * row start with the letter 's', then all cells in that row are highlighted with
  90.  * a red foreground. Also, as mentioned earlier, the highlighters are applied in
  91.  * the order they appear in the list.</p>
  92.  *
  93.  * @author Ramesh Gupta
  94.  * @see ComponentAdapter
  95.  * @see javax.swing.ListCellRenderer
  96.  * @see javax.swing.table.TableCellRenderer
  97.  * @see javax.swing.tree.TreeCellRenderer
  98.  */
  99. public class Highlighter {
  100.     /**
  101.      * Only one <code>ChangeEvent</code> is needed per model instance since the
  102.      * event's only (read-only) state is the source property.  The source
  103.      * of events generated here is always "this".
  104.      */
  105.     protected transient ChangeEvent changeEvent = null;
  106.     /** The listeners waiting for model changes. */
  107.     protected EventListenerList listenerList = new EventListenerList();
  108.     
  109.     /**
  110.      * Predefined <code>Highlighter</code> that highlights the background of
  111.      * each cell with a pastel green "ledger" background color, and is most
  112.      * effective when the {@link ComponentAdapter#target} component has
  113.      * horizontal gridlines in <code>Color.cyan.darker()</code> color.
  114.      */
  115.     public final static Highlighter ledgerBackground =
  116.                 new Highlighter(new Color(0xF5, 0xFF, 0xF5), null);
  117.     /**
  118.      * Predefined <code>Highlighter</code> that decorates the background of
  119.      * each cell with a pastel yellow "notepad" background color, and is most
  120.      * effective when the {@link ComponentAdapter#target} component has
  121.      * horizontal gridlines in <code>Color.cyan.darker()</code> color.
  122.      */
  123.     public final static Highlighter notePadBackground =
  124.                 new Highlighter(new Color(0xFF, 0xFF, 0xCC), null);
  125.     private Color background = null;
  126.     private Color foreground = null;
  127.     private Color selectedBackground = null;
  128.     private Color selectedForeground = null;
  129.     /**
  130.      * Default constructor.
  131.      * Initializes background, foreground, selectedBackground, and
  132.      * selectedForeground to null.
  133.      */
  134.     public Highlighter() {
  135.         // default constructor
  136.     }
  137.     /**
  138.      * Constructs a <code>Highlighter</code> with the specified
  139.      * background and foreground colors.
  140.      *
  141.      * @param cellBackground background color for the renderer, or null,
  142.      *          to compute a suitable background
  143.      * @param cellForeground foreground color for the renderer, or null,
  144.      *          to compute a suitable foreground
  145.      */
  146.     public Highlighter(Color cellBackground, Color cellForeground) {
  147.         this.background = cellBackground; // could be null
  148.         this.foreground = cellForeground; // could be null
  149.     }
  150.     /**
  151.      * Decorates the specified cell renderer component for the given component
  152.      * data adapter using highlighters that were previously set for the component.
  153.      * This method unconditionally invokes {@link #doHighlight doHighlight} with
  154.      * the same arguments as were passed in.
  155.      *
  156.      * @param renderer the cell renderer component that is to be decorated
  157.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  158.      * @return the decorated cell renderer component
  159.      */
  160.     public Component highlight(Component renderer, ComponentAdapter adapter) {
  161.         return doHighlight(renderer, adapter);
  162.     }
  163.     /**
  164.      * This is the bottleneck decorate method that all highlighters must invoke
  165.      * to decorate the cell renderer. This method invokes {@link #applyBackground
  166.      * applyBackground}, {@link #applyForeground applyForeground},
  167.      * {@link #applyFont applyFont} and so on, to decorate the corresponding
  168.      * attributes of the specified component within the given adapter.
  169.      *
  170.      * @param renderer the cell renderer component that is to be decorated
  171.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  172.      * @return the decorated cell renderer component
  173.      */
  174.     protected Component doHighlight(Component renderer, ComponentAdapter adapter) {
  175.         applyBackground(renderer, adapter);
  176.         applyForeground(renderer, adapter);
  177.         applyFont(renderer, adapter); // e.g., make it bold
  178.         // and so on...
  179.         return renderer;
  180.     }
  181.     /**
  182.      * Computes a suitable background for the renderer component within the
  183.      * specified adapter by calling {@link #computeBackground computeBackground}
  184.      * and applies the computed color to the component. If the computed
  185.      * color is null, it leaves the background unchanged; Otherwise it sets the
  186.      * component's background to the computed color.
  187.      *
  188.      * @param renderer the cell renderer component that is to be decorated
  189.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  190.      */
  191.     protected void applyBackground(Component renderer, ComponentAdapter adapter) {
  192.         Color color = computeBackground(renderer, adapter);
  193.         if (color != null) {
  194.             renderer.setBackground(color);
  195.         }
  196.     }
  197.     /**
  198.      * Computes a suitable foreground for the renderer component within the
  199.      * specified adapter by calling {@link #computeForeground computeForeground}
  200.      * and applies the computed color to the component. If the computed
  201.      * color is null, it leaves the foreground unchanged; Otherwise it sets the
  202.      * component's foreground to the computed color.
  203.      *
  204.      * @param renderer the cell renderer component that is to be decorated
  205.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  206.      */
  207.     protected void applyForeground(Component renderer, ComponentAdapter adapter) {
  208.         Color color = computeForeground(renderer, adapter);
  209.         if (color != null) {
  210.             renderer.setForeground(color);
  211.         }
  212.     }
  213.     /**
  214.      * Empty method. Override it to change the font of the renderer component.
  215.      *
  216.      * @param renderer the cell renderer component that is to be decorated
  217.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  218.      */
  219.     protected void applyFont(Component renderer, ComponentAdapter adapter) {
  220.         // must be overridden to cause any effect
  221.     }
  222.     /**
  223.      * <p>Computes a suitable background for the renderer component within the
  224.      * specified adapter and returns the computed color. The computed color
  225.      * depends on two factors: (i) whether the background color for this
  226.      * <code>Highlighter</code> is null or not, and (ii) whether the cell
  227.      * identified by the specified adapter
  228.      * {@link ComponentAdapter#isSelected isSelected} or not.</p>
  229.      *
  230.      * <p>If the background color for this <code>Highlighter</code> is not
  231.      * null, this method starts with an initial value that is equal to that
  232.      * background color, and proceeds to check the selected state of the cell.
  233.      * Otherwise, it starts with the background color of the component whose
  234.      * cell is being rendererd (not the background color of the renderer component
  235.      * that was passed in), and proceeds to check the selected state of the cell.</p>
  236.      *
  237.      * <p>If the cell identified by the specified adapter is selected, this
  238.      * method returns the value computed by
  239.      * {@link #computeSelectedBackground computeSelectedBackground} when passed
  240.      * the initial background color computed earlier. Otherwise, it simply
  241.      * returns the initial background color computed earlier.</p>
  242.      *
  243.      * @param renderer the cell renderer component that is to be decorated
  244.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  245.      * @return a suitable background color for the specified component and adapter
  246.      */
  247.     protected Color computeBackground(Component renderer, ComponentAdapter adapter) {
  248.         // If this.background is null, use adapter.target.getBackground();
  249.         // Never use renderer.getBackground() as the seed in this decorator
  250.         // class because renderer is too promiscuous!
  251.         Color seed = background == null ? adapter.target.getBackground() : background;
  252.         return adapter.isSelected() ? computeSelectedBackground(seed) : seed;
  253.     }
  254.     /**
  255.      * <p>Computes a suitable foreground for the renderer component within the
  256.      * specified adapter and returns the computed color. The computed color
  257.      * depends on two factors: (i) whether the foreground color for this
  258.      * <code>Highlighter</code> is null or not, and (ii) whether the cell
  259.      * identified by the specified adapter
  260.      * {@link ComponentAdapter#isSelected isSelected} or not.</p>
  261.      *
  262.      * <p>If the foreground color for this <code>Highlighter</code> is not
  263.      * null, this method starts with an initial value that is equal to that
  264.      * foreground color, and proceeds to check the selected state of the cell.
  265.      * Otherwise, it starts with the foreground color of the component whose
  266.      * cell is being rendererd (not the foreground color of the renderer component
  267.      * that was passed in), and proceeds to check the selected state of the cell.</p>
  268.      *
  269.      * <p>If the cell identified by the specified adapter is selected, this
  270.      * method returns the value computed by
  271.      * {@link #computeSelectedForeground computeSelectedBackground} when passed
  272.      * the initial foreground color computed earlier. Otherwise, it simply
  273.      * returns the initial foreground color computed earlier.</p>
  274.      *
  275.      * @param renderer the cell renderer component that is to be decorated
  276.      * @param adapter the {@link ComponentAdapter} for this decorate operation
  277.      * @return a suitable foreground color for the specified component and adapter
  278.      */
  279.     protected Color computeForeground(Component renderer, ComponentAdapter adapter) {
  280.         // If this.foreground is null, use adapter.target.getForeground();
  281.         // Never use renderer.getForeground() as the seed in this decorator
  282.         // class because renderer is too promiscuous!
  283.         Color seed = foreground == null ? adapter.target.getForeground() : foreground;
  284.         return adapter.isSelected() ? computeSelectedForeground(seed) : seed;
  285.     }
  286.     /**
  287.      * Computes the selected background color. If the selected background color
  288.      * of this <code>Highlighter</code> is not null, this method returns that
  289.      * color. Otherwise, it returns a {@link java.awt.Color#darker} version of
  290.      * the specified seed color.
  291.      *
  292.      * @param seed initial background color; must cope with null!
  293.      * @return the background color for a selected cell
  294.      */
  295.     protected Color computeSelectedBackground(Color seed) {
  296.         return selectedBackground == null ?
  297.             seed == null ? Color.gray : seed.darker() : selectedBackground;
  298.     }
  299.     /**
  300.      * Computes the selected foreground color. If the selected foreground color
  301.      * of this <code>Highlighter</code> is not null, this method returns that
  302.      * color. Otherwise, it returns {@link java.awt.Color#white}, ignoring the
  303.      * specified seed color. 
  304.      *
  305.      * @param seed initial foreground color; must cope with null!
  306.      * @return the foreground color for a selected cell
  307.      */
  308.     protected Color computeSelectedForeground(Color seed) {
  309.         return selectedForeground == null ? Color.white : selectedForeground;
  310.     }
  311.     /**
  312.      * Returns the background color of this <code>Highlighter</code>.
  313.      *
  314.      * @return the background color of this <code>Highlighter</code>,
  315.      *          or null, if no background color has been set
  316.      */
  317.     public Color getBackground() {
  318.         return background;
  319.     }
  320.     /**
  321.      * Sets the background color of this <code>Highlighter</code>.
  322.      *
  323.      * @param color the background color of this <code>Highlighter</code>,
  324.      *          or null, to clear any existing background color
  325.      */
  326.     public void setBackground(Color color) {
  327.         background = color;
  328.         fireStateChanged();
  329.     }
  330.     /**
  331.      * Returns the foreground color of this <code>Highlighter</code>.
  332.      *
  333.      * @return the foreground color of this <code>Highlighter</code>,
  334.      *          or null, if no foreground color has been set
  335.      */
  336.     public Color getForeground() {
  337.         return foreground;
  338.     }
  339.     /**
  340.      * Sets the foreground color of this <code>Highlighter</code>.
  341.      *
  342.      * @param color the foreground color of this <code>Highlighter</code>,
  343.      *          or null, to clear any existing foreground color
  344.      */
  345.     public void setForeground(Color color) {
  346.         foreground = color;
  347.         fireStateChanged();
  348.     }
  349.     /**
  350.      * Returns the selected background color of this <code>Highlighter</code>.
  351.      *
  352.      * @return the selected background color of this <code>Highlighter</code>,
  353.      *          or null, if no selected background color has been set
  354.      */
  355.     public Color getSelectedBackground() {
  356.         return selectedBackground;
  357.     }
  358.     /**
  359.      * Sets the selected background color of this <code>Highlighter</code>.
  360.      *
  361.      * @param color the selected background color of this <code>Highlighter</code>,
  362.      *          or null, to clear any existing selected background color
  363.      */
  364.     public void setSelectedBackground(Color color) {
  365.         selectedBackground = color;
  366.         fireStateChanged();
  367.     }
  368.     /**
  369.      * Returns the selected foreground color of this <code>Highlighter</code>.
  370.      *
  371.      * @return the selected foreground color of this <code>Highlighter</code>,
  372.      *          or null, if no selected foreground color has been set
  373.      */
  374.     public Color getSelectedForeground() {
  375.         return selectedForeground;
  376.     }
  377.     /**
  378.      * Sets the selected foreground color of this <code>Highlighter</code>.
  379.      *
  380.      * @param color the selected foreground color of this <code>Highlighter</code>,
  381.      *          or null, to clear any existing selected foreground color
  382.      */
  383.     public void setSelectedForeground(Color color) {
  384.         selectedForeground = color;
  385.         fireStateChanged();
  386.     }
  387.     /**
  388.      * Adds a <code>ChangeListener</code>.  The change listeners are run each
  389.      * time any one of the Bounded Range model properties changes.
  390.      *
  391.      * @param l the ChangeListener to add
  392.      * @see #removeChangeListener
  393.      * @see BoundedRangeModel#addChangeListener
  394.      */
  395.     public void addChangeListener(ChangeListener l) {
  396.         listenerList.add(ChangeListener.class, l);
  397.     }
  398.     
  399.     /**
  400.      * Removes a <code>ChangeListener</code>.
  401.      *
  402.      * @param l the <code>ChangeListener</code> to remove
  403.      * @see #addChangeListener
  404.      * @see BoundedRangeModel#removeChangeListener
  405.      */
  406.     public void removeChangeListener(ChangeListener l) {
  407.         listenerList.remove(ChangeListener.class, l);
  408.     }
  409.     /**
  410.      * Returns an array of all the change listeners
  411.      * registered on this <code>DefaultBoundedRangeModel</code>.
  412.      *
  413.      * @return all of this model's <code>ChangeListener</code>s 
  414.      *         or an empty
  415.      *         array if no change listeners are currently registered
  416.      *
  417.      * @see #addChangeListener
  418.      * @see #removeChangeListener
  419.      *
  420.      * @since 1.4
  421.      */
  422.     public ChangeListener[] getChangeListeners() {
  423.         return (ChangeListener[])listenerList.getListeners(
  424.                 ChangeListener.class);
  425.     }
  426.     /** 
  427.      * Runs each <code>ChangeListener</code>'s <code>stateChanged</code> method.
  428.      * 
  429.      * @see #setRangeProperties
  430.      * @see EventListenerList
  431.      */
  432.     protected void fireStateChanged() 
  433.     {
  434.         Object[] listeners = listenerList.getListenerList();
  435.         for (int i = listeners.length - 2; i >= 0; i -=2 ) {
  436.             if (listeners[i] == ChangeListener.class) {
  437.                 if (changeEvent == null) {
  438.                     changeEvent = new ChangeEvent(this);
  439.                 }
  440.                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  441.             }          
  442.         }
  443.     }   
  444.     
  445. }